简体   繁体   English

使用通用函数查询EF5中的DBSet

[英]Using a Generic Function to query a DBSet in EF5

I have seen various implementations of DbSet but I'm not sure they are what I am looking for. 我已经看到了DbSet的各种实现,但是不确定它们是否是我想要的。

Basically we have a bunch of DbSet's set up through EF5 Code First approach. 基本上,我们通过EF5 Code First方法建立了一堆DbSet。 I have a task of writing code to check any updates/posts coming into the API against the records we already have in the DB to make sure they only are updated/posted if they are new records. 我的任务是编写代码,以对照数据库中已有的记录来检查API中的任何更新/发布,以确保仅当它们是新记录时才进行更新/发布。

Obviously I don't want to write the same code for each of these DBSet's, I would like to write a single class/function that will be able to take in a DbSet as an argument/parameter and then check that DBSet for the record. 显然,我不想为每个DBSet编写相同的代码,我想编写一个单一的类/函数,该类/函数将DbSet作为参数/参数,然后检查该DBSet的记录。 It needs to be dynamic because it is dependant on the end user and what they are doing as to which DbSet will need to be queried... 它必须是动态的,因为它取决于最终用户以及他们要查询哪个DbSet的操作。

So for instance I want to do something like call: 因此,例如,我想做类似call的事情:

CheckDbUniqueRecord(Contracts) where Contracts is a DbSet of a Contract model that is being passed in from a form. CheckDbUniqueRecord(Contracts) ,其中Contracts是从表单传递来的Contract模型的DbSet。

So In the model we have public class Contract 因此,在模型中,我们有public class Contract

and in the MainDbContext we have multiple DbSet's one of which is public DbSet<Contract> Contracts {get; set;} 在MainDbContext中,我们有多个DbSet,其中之一是public DbSet<Contract> Contracts {get; set;} public DbSet<Contract> Contracts {get; set;}

I want to be able to run the same code to check for a duplicate record on any of the DbSets we have by simply passing in the class/model that is being returned from that particular controller with that one line function... 我希望能够运行相同的代码来检查我们拥有的任何DbSet上的重复记录,方法是简单地通过该行函数传入从特定控制器返回的类/模型...

I know there is a way to accomplish this but I keep getting error messages/type errors from C# saying the types don't match, etc... 我知道有一种方法可以做到这一点,但是我不断从C#收到错误消息/类型错误,说类型不匹配,等等。

any help would be greatly appreciated. 任何帮助将不胜感激。

UPDATE: I will only be needing this to check against duplicate records in the DB, not for updates. 更新:我将只需要检查数据库中的重复记录,而不需要更新。 I will handle the checking updates on the client side before calling the Put function. 在调用Put函数之前,我将在客户端处理检查更新。

I have the following code which is very nearly working: 我有以下几乎可以正常工作的代码:

public interface getId
        {
            int Id { get; set; }
        }
        public class Check : getId
        {
            public int Id { get; set; }

            public static bool CheckDBUniqueRecord<T>(T entity) where T : class, getId
            {
                MainDbContext db = new MainDbContext(Utility.PortalConnectionString());

                var myDbSet = db.Set<T>().ToList();

                foreach (var d in myDbSet)
                {
                    d.Id = 0;
                    if (d == entity) return true;

                }
                return false;


            }
        }

By using a generic constraint, however I am getting the error on the method call: The Type xxxx cannot be used as type parameter 'T' in the generic method yyyyyy. 但是,通过使用泛型约束,我在方法调用上遇到了错误:类型xxxx不能用作泛型方法yyyyyy中的类型参数'T'。 There is no implicit reference conversion from xxxx to yyyy. 从xxxx到yyyy没有隐式引用转换。

Whats the fix for this? 有什么解决办法?

first thing first: all of this is just written down and untested... 首先第一件事:所有这些都被写下并未经测试...

the first thing is simple: your functions signature... 第一件事很简单:您的函数签名...

public static bool CheckDbUniqueRecord<T>(T entity)

or something similar like an extensionmethod ... 或类似扩展方法的东西...

public static bool CheckDbUniqueRecord<T>(this DbContext db, T entity)

basically what you want to do is to query your DbContext for the DbSet that corresponds to your Entity ... 基本上,您要做的是在DbContext中查询与您的Entity相对应的DbSet ...

var myDbSet = db.Set<T>();

now you need some sort of logic to find out which properties you want to check for ... that can by done by placing attributes on your entity class members ... that can be done by checking everything that is not a primary key field ... you have to come up with something that tells you which things to test for ... for simplicity of this answer i'll just have some very simple thing that goes for every property with a getter that is not named "ID" ... depending on your implementation you will most likely want to move some of this code to an initialization code block that is not run every time... 现在,您需要某种逻辑来找出要检查的属性...可以通过在实体类成员上放置属性来完成...这可以通过检查不是主键字段的所有内容来完成。 ..您必须想出一些要告诉您要测试哪些内容的方法...为了简化此答案,我将为每个具有不名为“ ID”的吸气剂的属性提供一些非常简单的方法。 ..根据您的实现,您很可能希望将其中一些代码移到并非每次都运行的初始化代码块中。

var t = typeof(T);
var pInfos = t.GetProperties(BindingFlags.Public|BindingFlags.Instance).Where(x=>x.Name!="ID" && x.CanRead).ToArray();
Expression exp=null;
Expression pT = Expression.Parameter(t);
foreach(var p in pInfos)
{
Expression m = Expression.Property(pT,p);
Expression c = Expression.Constant(p.GetValue(entity));
if(tmp==null)
{
tmp=Expression.Equal(m,c);
}
else
{
tmp=Expression.AndAlso(tmp,Expression.Equal(m,c));
}
}
var myLambda=Expression.Lambda<Func<T,bool>>(tmp,pT);


return myDbSet.AsQueryable().Any(myLambda);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM