- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个在数据库中实现软删除的框架(称为 DeletedDate 的可空日期时间)。我正在使用存储库来处理主要实体请求,如下所示:
/// <summary>
/// Returns a Linq Queryable instance of the entity collection.
/// </summary>
public IQueryable<T> All
{
get { return Context.Set<T>().Where(e => e.DeletedDate == null); }
}
这很好用,但我遇到的问题是当您包含导航属性时,以及如何确保仅查询事件记录。有问题的存储库方法是这样开始的:
/// <summary>
/// Returns a Linq Queryable instance of the entity collection, allowing connected objects to be loaded.
/// </summary>
/// <param name="includeProperties">Connected objects to be included in the result set.</param>
/// <returns>An IQueryable collection of entity.</returns>
public IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = Context.Set<T>().Where(e => e.DeletedDate == null);
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
因此,如果 Repository 正被一个名为 Parent 的实体使用,该实体具有一个名为 Children 的导航属性,AllIncluding 方法将正确过滤掉软删除的 Parent 记录,但仍会包括软删除的 Children 记录。
查看发送到数据库的查询,似乎所有需要做的就是添加到 sql 连接子句“AND Children.DeletedDate IS NULL”,查询将返回正确的结果。
在我的研究过程中,我发现了 this post这似乎正是我所需要的,但是我的实现并没有得到与海报相同的结果。单步执行代码,查询的 Children 部分似乎没有发生任何事情。
这是我当前的相关代码(注意:使用 nuget 中的 QueryInterceptor):
基类:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DomainClasses
{
/// <summary>
/// Serves as the Base Class for All Data Model Classes
/// </summary>
public class BaseClass
{
/// <summary>
/// Default constructor, sets EntityState to Unchanged.
/// </summary>
public BaseClass()
{
this.StateOfEntity = DomainClasses.StateOfEntity.Unchanged;
}
/// <summary>
/// Indicates the current state of the entity. Not mapped to Database.
/// </summary>
[NotMapped]
public StateOfEntity StateOfEntity { get; set; }
/// <summary>
/// The entity primary key.
/// </summary>
[Key, Column(Order = 0), ScaffoldColumn(false)]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
/// <summary>
/// The date the entity record was created. Updated in InsightDb.SaveChanges() method
/// </summary>
[Column(Order = 1, TypeName = "datetime2"), ScaffoldColumn(false)]
public DateTime AddDate { get; set; }
/// <summary>
/// The UserName of the User who created the entity record. Updated in InsightDb.SaveChanges() method
/// </summary>
[StringLength(56), Column(Order = 2), ScaffoldColumn(false)]
public string AddUser { get; set; }
/// <summary>
/// The date the entity record was modified. Updated in InsightDb.SaveChanges() method
/// </summary>
[Column(Order = 3, TypeName = "datetime2"), ScaffoldColumn(false)]
public DateTime ModDate { get; set; }
/// <summary>
/// The UserName of the User who modified the entity record.
/// </summary>
[StringLength(56), Column(Order = 4), ScaffoldColumn(false)]
public string ModUser { get; set; }
/// <summary>
/// Allows for Soft Delete of records.
/// </summary>
[Column(Order = 5, TypeName = "datetime2"), ScaffoldColumn(false)]
public DateTime? DeletedDate { get; set; }
}
}
父类:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace DomainClasses
{
/// <summary>
/// The Parent Entity.
/// </summary>
public class Parent : BaseClass
{
/// <summary>
/// Instantiates a new instance of Parent, initializes the virtual sets.
/// </summary>
public Parent()
{
this.Children = new HashSet<Child>();
}
#region Properties
/// <summary>
/// The Parent's Name
/// </summary>
[StringLength(50), Required, Display(Name="Parent Name")]
public string Name { get; set; }
#endregion
#region Relationships
/// <summary>
/// Relationship to Child, 1 Parent = Many Children.
/// </summary>
public virtual ICollection<Child> Children { get; set; }
#endregion
}
}
子类:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DomainClasses
{
/// <summary>
/// The Child entity. One Parent = Many Children
/// </summary>
public class Child : BaseClass
{
#region Properties
/// <summary>
/// Child Name.
/// </summary>
[Required, StringLength(50), Display(Name="Child Name")]
public string Name { get; set; }
#endregion
#region Relationships
/// <summary>
/// Parent Relationship. 1 Parent = Many Children.
/// </summary>
public virtual Parent Parent { get; set; }
#endregion
}
}
上下文类:
using DomainClasses;
using System;
using System.Data;
using System.Data.Entity;
using System.Linq;
namespace DataLayer
{
public class DemoContext : DbContext, IDemoContext
{
/// <summary>
/// ActiveSession object of the user performing the action.
/// </summary>
public ActiveSession ActiveSession { get; private set; }
public DemoContext(ActiveSession activeSession)
: base("name=DemoDb")
{
ActiveSession = activeSession;
this.Configuration.LazyLoadingEnabled = false;
}
#region Db Mappings
public IDbSet<Child> Children { get; set; }
public IDbSet<Parent> Parents { get; set; }
#endregion
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<BaseClass>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
entry.Entity.ModDate = DateTime.UtcNow;
entry.Entity.ModUser = ActiveSession.UserName;
if (entry.State == EntityState.Added)
{
entry.Entity.AddDate = DateTime.UtcNow;
entry.Entity.AddUser = ActiveSession.UserName;
}
else if (entry.State == EntityState.Deleted)
{
entry.State = EntityState.Modified;
entry.Entity.DeletedDate = DateTime.UtcNow;
}
}
}
return base.SaveChanges();
}
public new IDbSet<T> Set<T>() where T : BaseClass
{
return ((DbContext)this).Set<T>();
}
}
}
存储库类:
using DomainClasses;
using QueryInterceptor;
using System;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace DataLayer
{
/// <summary>
/// Entity Repository to be used in Business Layer.
/// </summary>
public class EntityRepository<T> : IEntityRepository<T> where T : BaseClass
{
public IDemoContext Context { get; private set; }
/// <summary>
/// Main Constructor for Repository. Creates an instance of DemoContext (derives from DbContext).
/// </summary>
/// <param name="activeSession">UserName of the User performing the action.</param>
public EntityRepository(ActiveSession activeSession)
: this(new DemoContext(activeSession))
{
}
/// <summary>
/// Constructor for Repository. Allows a context (i.e. FakeDemoContext) to be passed in for testing.
/// </summary>
/// <param name="context">IDemoContext to be used in the repository. I.e. FakeDemoContext.</param>
public EntityRepository(IDemoContext context)
{
Context = context;
}
/// <summary>
/// Returns a Linq Queryable instance of the entity collection.
/// </summary>
public IQueryable<T> All
{
get { return Context.Set<T>().Where(e => e.DeletedDate == null); }
}
/// <summary>
/// Returns a Linq Queryable instance of the entity collection, allowing connected objects to be loaded.
/// </summary>
/// <param name="includeProperties">Connected objects to be included in the result set.</param>
/// <returns>An IQueryable collection of entity.</returns>
public IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = Context.Set<T>().Where(e => e.DeletedDate == null);
InjectConditionVisitor icv = new InjectConditionVisitor();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query.InterceptWith(icv);
}
/// <summary>
/// Finds a single instance of the entity by the Id.
/// </summary>
/// <param name="id">The primary key for the entity.</param>
/// <returns>An instance of the entity.</returns>
public T Find(int id)
{
return Context.Set<T>().Where(e => e.DeletedDate == null).SingleOrDefault(e => e.Id == id);
}
/// <summary>
/// Takes a single entity or entity graph and reads the explicit state, then applies the necessary State changes to Update or Add the entities.
/// </summary>
/// <param name="entity">The entity object.</param>
public void InsertOrUpdate(T entity)
{
if (entity.StateOfEntity == StateOfEntity.Added)
{
Context.Set<T>().Add(entity);
}
else
{
Context.Set<T>().Add(entity);
Context.ApplyStateChanges();
}
}
/// <summary>
/// Deletes the instance of the entity.
/// </summary>
/// <param name="id">The primary key of the entity.</param>
public void Delete(int id)
{
var entity = Context.Set<T>().Where(e => e.DeletedDate == null).SingleOrDefault(e => e.Id == id);
entity.StateOfEntity = StateOfEntity.Deleted;
Context.Set<T>().Remove(entity);
}
/// <summary>
/// Saves the transaction.
/// </summary>
public void Save()
{
Context.SaveChanges();
}
/// <summary>
/// Disposes the Repository.
/// </summary>
public void Dispose()
{
Context.Dispose();
}
}
}
InjectConditionVisitor 类:
using System;
using System.Linq;
using System.Linq.Expressions;
namespace DataLayer
{
public class InjectConditionVisitor : ExpressionVisitor
{
private QueryConditional queryCondition;
public InjectConditionVisitor(QueryConditional condition)
{
queryCondition = condition;
}
public InjectConditionVisitor()
{
queryCondition = new QueryConditional(x => x.DeletedDate == null);
}
protected override Expression VisitMember(MemberExpression ex)
{
// Only change generic types = Navigation Properties
// else just execute the normal code.
return !ex.Type.IsGenericType ? base.VisitMember(ex) : CreateWhereExpression(queryCondition, ex) ?? base.VisitMember(ex);
}
/// <summary>
/// Create the where expression with the adapted QueryConditional
/// </summary>
/// <param name="condition">The condition to use</param>
/// <param name="ex">The MemberExpression we're visiting</param>
/// <returns></returns>
private Expression CreateWhereExpression(QueryConditional condition, Expression ex)
{
var type = ex.Type;//.GetGenericArguments().First();
var test = CreateExpression(condition, type);
if (test == null)
return null;
var listType = typeof(IQueryable<>).MakeGenericType(type);
return Expression.Convert(Expression.Call(typeof(Enumerable), "Where", new Type[] { type }, (Expression)ex, test), listType);
}
/// <summary>
/// Adapt a QueryConditional to the member we're currently visiting.
/// </summary>
/// <param name="condition">The condition to adapt</param>
/// <param name="type">The type of the current member (=Navigation property)</param>
/// <returns>The adapted QueryConditional</returns>
private LambdaExpression CreateExpression(QueryConditional condition, Type type)
{
var lambda = (LambdaExpression)condition.Conditional;
var conditionType = condition.Conditional.GetType().GetGenericArguments().FirstOrDefault();
// Only continue when the condition is applicable to the Type of the member
if (conditionType == null)
return null;
if (!conditionType.IsAssignableFrom(type))
return null;
var newParams = new[] { Expression.Parameter(type, "bo") };
var paramMap = lambda.Parameters.Select((original, i) => new { original, replacement = newParams[i] }).ToDictionary(p => p.original, p => p.replacement);
var fixedBody = ParameterRebinder.ReplaceParameters(paramMap, lambda.Body);
lambda = Expression.Lambda(fixedBody, newParams);
return lambda;
}
}
}
查询条件类:
using DomainClasses;
using System;
using System.Linq.Expressions;
namespace DataLayer
{
public class QueryConditional
{
public QueryConditional(Expression<Func<BaseClass, bool>> ex)
{
Conditional = ex;
}
public Expression<Func<BaseClass, bool>> Conditional { get; set; }
}
}
ParameterRebinder 类:
using System.Collections.Generic;
using System.Linq.Expressions;
namespace DataLayer
{
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression node)
{
ParameterExpression replacement;
if (map.TryGetValue(node, out replacement))
node = replacement;
return base.VisitParameter(node);
}
}
}
IEntityRepository 接口(interface):
using System;
using System.Linq;
using System.Linq.Expressions;
namespace DataLayer
{
public interface IEntityRepository<T> : IDisposable
{
IQueryable<T> All { get; }
IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties);
T Find(int id);
void InsertOrUpdate(T entity);
void Delete(int id);
void Save();
}
}
IDemoContext 接口(interface):
using DomainClasses;
using System;
using System.Data.Entity;
namespace DataLayer
{
public interface IDemoContext : IDisposable
{
ActiveSession ActiveSession { get; }
IDbSet<Child> Children { get; }
IDbSet<Parent> Parents { get; }
int SaveChanges();
IDbSet<T> Set<T>() where T : BaseClass;
}
}
最佳答案
问题是您想在 AllIncluding 方法中使用 Include() 语句添加条件。 queryinterceptor 包不支持 Include() 方法。使此工作正常进行的唯一解决方案是不使用 Include 语句。
当您执行以下操作时一切正常:
Articles.Select(x => new {
Vat = x.VatTypes
})
.InterceptWith(Visitor);
因此,当将上述内容转换为 sql 时,您会看到查询中添加了一个 Where VatTypes.IsDeleted = 0。
是否真的有必要使用 includeAll 方法,从性能的角度来看,这在我看来是一个巨大的开销,因为您要从数据库中加载所有内容。
编辑:再次阅读一些较旧的帖子后,看起来实际上应该可以将 InterceptWith 方法与 Include() 语句一起使用。也许是 ExpressionVisitor 与 Include() 有问题。如果我有时间,我会试试这个并回复你。
关于c# - 使用 ExpressionVisitor 排除连接中的软删除记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17532393/
我有一个名为“members”的数据库表。分配给成员的是一个职位。 职位 来自部门。我有 Departments,然后是那些中的 Sub-Departments 和 Sub-Departments 中
我正在尝试为 Solr 搜索应用过滤器标记 Tagging_and_excluding_Filters . 挑战在于同时应用多个标记(对于单个页面上的多个选择选项)。例如 q=mainquery&fq
我知道这个问题已经被问过很多次了,我已经尝试了所有建议,并阅读了有关不同选择器等的所有内容,但没有任何对我有用 给出以下 HTML 片段: link
是否有直接的 LINQ 语法来查找集合 B 中不存在的集合 A 的成员?在 SQL 我会写这个 SELECT A.* FROM A LEFT JOIN B ON A.ID = B.ID WHERE B
我试图排除并在现有xpath中包括以下xpath,但不太确定如何做到这一点 //exclude -> //*[@id="ires"]/ol/li[6]/div/a[1]/img //include
我有 30 个站点,我需要在其中 24 个站点上回显某些内容。我怎样才能排除其他人?该代码不起作用,因为我认为它的逻辑是假的:) $currentsite = get_bloginfo('wpurl'
我需要对目标文件夹进行检查,并检查文件是否来自今天,并且超过5kb 下面的命令根据使用今天的日期存在的文件来提供bool值,但是我还要添加-gt5kb之类的排除项 我尝试使用-Exlcude,但不确定
我编入索引的Elasticsearch文档包含许多字段。我一直在使用match_all查询来获取结果。我想从match_all中排除一些字段,这可能吗? 最佳答案 在Elasticsearch中,您可
我正在为我的 DAO 编写一些测试,因为很多测试使用保存到我的数据库中的测试对象,所以我使用注释 @Before 和 @Before 创建了 setup() 和teardown() 方法@After
我编写了一个程序来解决以下问题: Implement a diffusion limited aggregation simulation on a toroid plane where seeds
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
很多时候我必须运行这个查询: select * from users where name is not null and name != '' 有没有更好的方法来做到这一点。我需要更多的性能,任何建
如果检测到某个操作系统,是否有一种简单的方法可以排除某些代码? 我设计了一个运行良好的网站(它是一个 sidescroller),当使用滚轮(向上/向下)时,它会左右滚动。但是,如果您使用的是 Mac
我应该如何排除“IN”子句中的值? $Graduates = "45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,6
很明显,如果一个 Mysql 表的全文索引包含一个出现在 50% 的数据行中的关键字,该关键字将被匹配查询忽略 因此,如果我有一个包含 50 个条目的全文索引“content”的表其中 27 个条目在
我有下面的循环。 我需要提取所有不包含字母 p 的名称 (lskey),但我的尝试不起作用。 for(var i = 0; i "); } } 如果有人能回答,我将不胜感激。 最佳答案 如此接
我正在尝试查找 FTP 服务器上根目录的总大小。但是,我无权访问根目录中的其中一个目录。 我想用这个函数对根目录的大小求和: size = 0 for filename in ftp.nlst("."
我有以下正则表达式来匹配 html 链接: 有点效果。除了不是真的。因为它在 编辑: 这将使它只抓取引号而不是 之后的所有内容 最佳答案 我认为您的正则表达式没有按照您的意愿行事。 这会非贪婪地捕
我在提出异常方面遇到困难,例如: import csv o = open('/home/foo/dummy.csv', 'r') # Empty file! reader = csv.reader(o
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我是一名优秀的程序员,十分优秀!