简体   繁体   English

我应该如何禁用每个对象的实体框架表引用(外部)列表?

[英]How should I disable Entity Framework table reference(foreign) list from each objects?

I'm using Sqlite database and System.Data.SQLite 1.0.92 There is 2 table here:我正在使用Sqlite 数据库System.Data.SQLite 1.0.92这里有 2 个表:


Table Person :表人

PersonId人名

PersonName人名


Table Student :表学生

StudentId学生卡

PersonId(reference table Person FK) PersonId(参考表Person FK)

StudentNo学生号


Now every time I get the Persons Collection in EF5:现在每次我在 EF5 中获得 Persons 集合时:

using (var ctx = new myEntities)
{
  AllPersons = ctx.Persons.ToList();
}

There is also has AllPersons.student collection will include in the result;也有AllPersons.student集合会包含在结果中;

But I don't need it.但我不需要它。 Of course that's just an example, There is a lot of big table has so many references, it always has performance problems here because of that.当然这只是一个例子,有很多大表有这么多引用,因此它总是有性能问题。

So I'm trying to do not let it in my result.所以我试图不让它出现在我的结果中。 So I change it:所以我改变它:

using (var ctx = new myEntities)
{
      ctx.Configuration.ProxyCreationEnabled = false;
      ctx.Configuration.LazyLoadingEnabled = false;
      AllPersons= ctx.Persons.ToList();
}

Now fine, because AllPersons.student collection will always be null现在很好,因为AllPersons.student集合将始终为null

But now I found: If I get Person and Student together :但现在我发现:如果我把 Person 和 Student放在一起

using (var ctx = new myEntities)
{
    ctx.Configuration.ProxyCreationEnabled = false;
    ctx.Configuration.LazyLoadingEnabled = false;
    AllPersons= ctx.Persons.ToList();
    AllStudents = ctx.Student.ToList();
}

Now the reference still include in.现在参考仍然包含在。

So Is there anyway to don't let the reference include in any time in this situation?那么在这种情况下,无论如何不要让参考包含在任何时候? Thank you.谢谢你。


Update更新

For some friends request, I explain why I need it:对于一些朋友的要求,我解释一下为什么我需要它:

1: When I convert it to json it will be a dead loop. 1:当我将其转换为 json 时,它将是一个死循环。 even I already use Json.net ReferenceLoopHandling , the json size very big to crash the server.(if no references, it's just a very small json)甚至我已经使用 Json.net ReferenceLoopHandling ,json 大小非常大,导致服务器崩溃。(如果没有引用,它只是一个非常小的 json)

2:Every time I get the client data and need to save, it will display exception about model state, until I set it to null . 2:每次获取客户端数据需要保存时,都会显示模型状态异常,直到我将其设置为null

Example:例子:

using (myEntities ctx = new myEntities())
 {
 ctx.Configuration.LazyLoadingEnabled = false;
 ctx.Configuration.ProxyCreationEnabled = false;



  Person model= ThisIsAModel();

  model.students = null;  // This is a key, I need set the students collection references to null , otherwise it will throw exception

  ctx.Entry(model).State = EntityState.Modified;
  ctx.SaveChanges();

}

3: This is More important problem. 3:这是更重要的问题。 I already get all data and cache on the server.我已经在服务器上获取了所有数据和缓存。 But It will let the loading time very long when server start.但它会让服务器启动时加载时间很长。 (because the data and references are so many, that is the main problem), I don't know I'll meet what kind of problem again.... (因为数据和参考文献太多了,这才是主要问题),不知道又会遇到什么样的问题....

public List<Person> PersonsCache; // global cache
public List<Student> StudentsCache; // global cache
using (myEntities ctx = new myEntities())
 {
     ctx.Configuration.LazyLoadingEnabled = false;
     ctx.Configuration.ProxyCreationEnabled = false;
 // There is so many references and data, will let it very slow , when I first time get the all cache. even I only get the Person model, not other , just because some Collection has some references problem. It will very slow....

   PersonsCache = ctx.Persons.ToList();
   StudentsCache= ctx.Student.ToList();
}

The Problem问题

As you said, when you load both of Parent and Child lists even when LazyLoading is disabled, and then look in parent.Childs you see child items has been loaded too.正如您所说,当您加载父和子列表时,即使禁用了 LazyLoading,然后查看 parent.Childs,您也会看到子项也已加载。

var db = new YourDbContext();
db.Configuration.LazyLoadingEnabled = false;
var parentList= db.YourParentSet.ToList();
var childList= db.YourChildSet.ToList();

What happened?发生了什么? Why childs are included in a parent?为什么孩子包含在父母中?

The childs under a parent entity, are those you loaded using db.YourChildSet.ToList();父实体下的子项是您使用db.YourChildSet.ToList();加载的子db.YourChildSet.ToList(); Exactly themselves ;正是他们自己 In fact Entity Framework never loads childs for a parent again but because of relation between parent and child in edmx, they are listed there.事实上,Entity Framework 永远不会再次为父级加载子级,但由于 edmx 中父级和子级之间的关系,它们被列在那里。


Is that affect Perforemance?那会影响性能吗?

According to the fact that childs only load once, It has no impact on perforemance because of loading data.根据childs只加载一次的事实,不会因为加载数据而影响性能。


But for serialization or something else's sake, How can I get rid of it?但是为了序列化或其他原因,我该如何摆脱它?

you can use these solutions:您可以使用这些解决方案:

Solution 1:解决方案1:

Use 2 different instance of YourDbContext:使用 2 个不同的 YourDbContext 实例:

var db1 = new YourDbContext();
db1.Configuration.LazyLoadingEnabled = false;
var parentList= db.YourParentSet.ToList();

var db2 = new YourDbContext();
db2.Configuration.LazyLoadingEnabled = false;
var childList= db.YourChildSet.ToList();
  • Now when you look in parent.Childs there is no Child in it.现在,当您查看 parent.Childs 时,其中没有 Child。

Solution 2:解决方案2:

use Projection and shape your output to your will and use them.使用投影并根据您的意愿塑造您的输出并使用它们。

var db1 = new YourDbContext();
db1.Configuration.LazyLoadingEnabled = false;
var parentList= db.YourParentSet
                  .Select(x=>new /*Model()*/{
                      Property1=x.Property1,
                      Property2=x.Property2, ...
                  }).ToList();
  • This way when serialization there is nothing annoying there.这样在序列化时就没有什么烦人的了。
  • Using a custom Model class is optional and in some cases is recommended.使用自定义模型类是可选的,在某些情况下是推荐的。

Additional Resources其他资源

As a developer who use Entity Framework reading these resources is strongly recommended:作为使用实体框架的开发人员,强烈建议阅读这些资源:

I'll focus on your third problem because that seems to be your most urgent problem.我将专注于您的第三个问题,因为这似乎是您最紧迫的问题。 Then I'll try to give some hints on the other two problems.然后我会尝试对另外两个问题给出一些提示。

There are two Entity Framework features you should be aware of:您应该注意两个实体框架功能:

  1. When you load data into a context, Entity Framework will try to connect the objects wherever they're associated.当您将数据加载到上下文中时,实体框架将尝试在对象关联的任何位置连接对象。 This is called relationship fixup .这称为关系修正 You can't stop EF from doing that.你不能阻止 EF 这样做。 So if you load Persons and Students separately, a Person 's Students collection will contain students, even though you didn't Include() them.因此,如果您分别加载PersonsStudentsPersonStudents集合包含学生,即使您没有Include()他们。

  2. By default, a context caches all data it fetches from the database.默认情况下,上下文缓存它从数据库中获取的所有数据。 Moreover, it stores meta data about the objects in its change tracker: copies of their individual properties and all associations.此外,它将有关对象的元数据存储在其更改跟踪器中:它们的各个属性所有关联的副本。 So by loading many objects the internal cache grows, but also the size of the meta data.因此,通过加载许多对象,内部缓存会增加,但元数据的大小也会增加。 And the ever-running relationship fixup process gets slower and slower (although it may help to postpone it by turning off automatic change detection).并且不断运行的关系修复过程变得越来越慢(尽管通过关闭自动更改检测可能有助于推迟它)。 All in all, the context gets bloated and slow like a flabby rhino.总而言之,上下文变得臃肿和缓慢,就像一头松弛的犀牛。

I understand you want to cache data in separate collections for each entity.我了解您希望为每个实体在单独的集合中缓存数据。 Two simple modifications will make this much quicker:两个简单的修改将使这更快:

  • Evade the inevitable relationship fixup by loading each collection by a separate context通过单独的上下文加载每个集合来避免不可避免的关系修复
  • Stop caching (in the context) and change tracking by getting the data with AsNoTracking .停止缓存(在上下文中)并通过使用AsNoTracking获取数据来更改跟踪。

Doing this, your code will look like this:这样做,您的代码将如下所示:

public List<Person> PersonsCache;
public List<Student> StudentsCache;

using (myEntities ctx = new myEntities())
{
     ctx.Configuration.ProxyCreationEnabled = false;
     PersonsCache = ctx.Persons
                       .AsNoTracking()
                       .ToList();
}

using (myEntities ctx = new myEntities())
{
     ctx.Configuration.ProxyCreationEnabled = false;
     StudentsCache= ctx.Student
                       .AsNoTracking()
                       .ToList();
}

The reason for turning off ProxyCreationEnabled is that you'll get light objects and that you'll never inadvertently trigger lazy loading afterwards (throwing an exception that the context is no longer available).关闭ProxyCreationEnabled的原因是您将获得轻量级对象,并且之后您永远不会无意中触发延迟加载(抛出上下文不再可用的异常)。

Now you'll have cached objects that are not inter-related and that get fetched as fast as it gets with EF.现在,您将拥有不相互关联的缓存对象,并且可以像使用 EF 一样快速获取这些对象。 If this isn't fast enough you'll have to resort to other tools, like Dapper.如果这还不够快,您将不得不求助于其他工具,例如 Dapper。

By the way, your very first code snippet and problem description...顺便说一句,你的第一个代码片段和问题描述......

 using (var ctx = new myEntities) { AllPersons = ctx.Persons.ToList(); }

There is also has AllPersons.student collection will include in the result;也有 AllPersons.student 集合会包含在结果中;

...suggest that Entity Framework spontaneously performs eager loading (of students) without you Include -ing them. ...建议实体框架自发地执行(学生)的热切加载,而无需Include -ing 他们。 I have to assume that your code snippet is not complete.我必须假设您的代码片段不完整。 EF never, ever automatically executes eager loading. EF 永远不会自动执行预先加载。 (Unless, maybe, you have some outlandish and buggy query provider). (除非,也许,您有一些古怪且有问题的查询提供程序)。

As for the first problem , the serialization.至于第一个问题,序列化。 You should be able to tackle that in a similar way as shown above.您应该能够以如上所示的类似方式解决该问题。 Just load the data you want to serialize in isolation and disable proxy creation.只需加载要单独序列化的数据并禁用代理创建。 Or, as suggested by others, serialize view models or anonymous types exactly containing what you need there.或者,正如其他人所建议的,序列化完全包含您需要的视图模型或匿名类型。

As for the second problem , the validation exception.至于第二个问题,验证异常。 I can only imagine this to happen if you initialize a students collection by default, empty, Student objects.我只能想象如果您默认初始化学生集合,空的Student对象会发生这种情况。 These are bound to be invalid.这些肯定是无效的。 If this is not the case, I suggest you ask a new question about this specific problem, showing ample detail about the involved classes and mappings.如果不是这种情况,我建议您就这个特定问题提出一个新问题,显示有关所涉及的类和映射的足够详细信息。 That shouldn't be dealt with in this question.不应该在这个问题中处理。

Explicitly select what you want to return from the Database.明确选择要从数据库返回的内容。

Use Select new .使用Select new With the select new clause, you can create new objects of an anonymous type as the result of a query and don't let the reference include in. This syntax allows you to construct anonymous data structures.使用select new子句,您可以创建匿名类型的新对象作为查询的结果,并且不要让引用包含在其中。此语法允许您构造匿名数据结构。 These are created as they are evaluated (lazily).这些是在评估(懒惰)时创建的。 Like this:像这样:

using (var ctx = new myEntities())
{
     var AllPersons = ctx.People.Select(c => new {c.PersonId, c.PersonName}).ToList();
}

And even you don't need to disable lazy loading anymore .甚至您也不再需要禁用延迟加载

After running query above:运行上面的查询后:

结果

This query currently allocates an anonymous type using select new { } , which requires you to use var .此查询当前使用select new { }分配匿名类型,这需要您使用var If you want allocate a known type, add it to your select clause:如果要分配已知类型,请将其添加到 select 子句中:

private IEnumerable<MyClass> AllPersons;//global variable

using (var ctx = new myEntities())
{
     AllPersons = ctx.People
         .Select(c => new MyClass { PersonId = c.PersonId, PersonName = c.PersonName }).ToList();
}

And:和:

public class MyClass
{
    public string PersonId { get; set; }
    public string PersonName { get; set; }
}

If entities are auto generated, then copy paste it to own code and remove the relation generated like child collection and Foreign key.如果实体是自动生成的,则将其复制粘贴到自己的代码中并删除生成的关系,如子集合和外键。 Or you don't need all this kind of the functionality might be can user lightweight framework like dapper或者你不需要所有这些功能,可以使用像dapper这样的轻量级框架

In normally your student collection doesn't fill from database.通常,您的学生收藏不会从数据库中填充。 it's fill when you reach to property.当您到达财产时,它已满。 In addition if you use ToList() method so Entity Framework read data from data to fill your collection.此外,如果您使用 ToList() 方法,那么实体框架将从数据中读取数据以填充您的集合。

Pls check this.请检查这个。 https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazy https://msdn.microsoft.com/en-us/library/vstudio/dd456846(v=vs.100).aspx https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazy https://msdn.microsoft.com/en-us/library/vstudio/dd456846(v=vs.100).aspx

Is there anyway to don't let the reference include in any time in this situation?在这种情况下,无论如何不要让参考文献包含在任何时候

The solution to this seems to be very simple: don't map the association.解决这个问题的方法似乎很简单:不要映射关联。 Remove the Student collection.删除Student集合。 Not much more I can say about it.我不能再多说了。

If I understand you correctly, you're just trying to make sure you only get what you specifically ask for right?如果我理解正确,你只是想确保你只得到你特别要求的东西,对吗?

This was mentioned a little above, but to do this correctly you just want to select an anonymous type.上面提到了一点,但要正确执行此操作,您只需选择一个匿名类型。

var students = from s in _context.Students
               select new{
               StudentId,
               StudentNo};

Then, when you want to update this collection/object, I'd recommend use GraphDiff.然后,当你想更新这个集合/对象时,我建议使用 GraphDiff。 GraphDiff really helps with the problems of disconnected entities and updates ( https://github.com/refactorthis/GraphDiff ) GraphDiff 确实有助于解决断开连接的实体和更新的问题( https://github.com/refactorthis/GraphDiff

So your method would look similar to this:所以你的方法看起来类似于:

void UpdateStudent(Student student){
   _context.UpdateGraph(student, map =>
                    map
                        .AssociatedEntity(c => c.Person));
_context.SaveChanges();
}

This way, you're able to update whatever properties on an object, disconnected or not, and not worry about the association.这样,您就可以更新对象上的任何属性,无论是否断开连接,而不必担心关联。

This is assuming that you correctly mapped your entities, and honestly, I find it easier to declare the object as a property, not just the ID, and use a mapping file to map it correctly.这是假设您正确映射了实体,老实说,我发现将对象声明为属性(而不仅仅是 ID)并使用映射文件正确映射它更容易。

So:所以:

class Person{
int Id{get;set;}
string Name{get;set}
}

class Student{
int Id{get;set;}
string StudentNo{get;set;}
Person Person{get;set;}

public class StudentMap : EntityTypeConfiguration<Student>
    {
        public StudentMap()
        {
            // Primary Key
            HasKey(t => t.Id);


            // Table & Column Mappings
            ToTable("Students");
            Property(t => t.Id).HasColumnName("StudentId");

           // Relationships
            HasRequired(t => t.Person)                
                .HasForeignKey(d => d.PersonId);
  }
}

Hopefully that makes sense.希望这是有道理的。 You don't need to create a view model, but you definitely can.您不需要创建视图模型,但您绝对可以。 This way does make it easier to map disconnected items back to the database though.但是,这种方式确实可以更轻松地将断开连接的项目映射回数据库。

I had exact same situation.我有完全相同的情况。 All I did to solve it was ask for the Student.ToList() before I asked for Persons.ToList() I didn't have to disable lazy loading.在我要求 Persons.ToList() 之前,我为解决它所做的只是要求 Student.ToList() 我不必禁用延迟加载。 Just need to load the table that has reference to other table first after that you can load the other table and first table results are already in memory and don't get "fixed" with all the references.只需要先加载引用其他表的表,然后您就可以加载其他表,并且第一个表结果已经在内存中,并且不会对所有引用进行“修复”。

They are automatically linked in the ObjectContext by there EntityKey .它们通过EntityKey自动链接到ObjectContext Depending on what you want to do with your Persons and Students , you can Detach them from the ObjectContext :根据您想对PersonsStudents做什么,您可以将它们从ObjectContext Detach出来:

using (var ctx = new myEntities)
{
    ctx.Configuration.ProxyCreationEnabled = false;
    ctx.Configuration.LazyLoadingEnabled = false;
    AllPersons= ctx.Persons.ToList();
    foreach(var c in AllPersons)
    {
        ctx.Detach(c);
    }
    AllStudents = ctx.Student.ToList();
    foreach(var c in AllStudents )
    {
        ctx.Detach(c);
    }
}

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

相关问题 使用实体框架,如何在两个模型上添加外键以相互引用 - Using Entity Framework, how can I add a foreign key on two models to reference each other 从具有外键的表查询时如何禁用实体框架自动连接 - How to disable Entity Framework auto join when querying from table with foreign key 如何使用Entity Framework将多个对象添加到外表 - How to add multiple objects to a foreign table using Entity Framework 我应该将外键表存储为Entity Framework中的外键ID还是该表的C#模型? - Should I store foreign key table as foreign key ID or the C# model of that table in Entity Framework? 如何使用实体框架查询外键对象? - How can I query the foreign key objects using Entity Framework? 实体框架:如何删除相互引用的表行? - Entity Framework: How do I delete table rows that reference each other? 如何最好在Entity Framework中重命名引用? - How should I rename a reference in Entity Framework best? 如何在实体框架中为外键指定表? - How do I specify table for foreign key in entity framework? 如何在Entity Framework 6中使用Fluent API映射没有外键属性的一对多对象列表? - How can I use Fluent API in Entity Framework 6 to Map a List of One To Many objects without a foreign key property? 如何更新与Entity Framework中的另一个表联接的表? - How should I update a table that is joined with another table in Entity Framework?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM