2011-06-23 40 views
4

假设我有一个多行的文件,每一个代表一个Person,该Person实体有一个identity column这也是primary key。假设一个Person可以在文件中重复,如果是的话,也许我想要做一个最后的入场场景。在下面的示例中,我使用存储库通过社会安全号从数据库检索人员。问题是,当同一个SSN再次出现在文件中时,即使技术上该SSN的用户已被添加到上下文中(SaveChanges尚未被调用),该存储库仍会返回空值。我意识到我可以通过跟踪自己已经添加了哪些对象。我想知道这种情况下的最佳做法是什么。 谢谢。检索实体添加()之后,但之前的SaveChanges()被调用

foreach(row in fileRows) 
{ 
    Person person = personRepository.GetBySSN(row.SSN); 

    if(person == null) 
    { 
     //insert logic 
    } 
    else 
    { 
     //update logic 
    } 
} 

personRepository.SaveChanges(); 
+0

重复? http://stackoverflow.com/questions/5719990/how-do-i-view-an-entityset-and-uncommitted-changes http://stackoverflow.com/questions/5383485/entity-framework-4-and-transactions -do-uncommitted-changes-affect-select-results – Holystream

+0

我恭敬地不同意。即使这些是类似的主题,我想知道在通过存储库进行操作时最佳做法是什么。我意识到如果我可以直接访问EF环境,我将能够找出是否添加了某个SSN。因为我通过抽象存储库工作,所以我想知道最佳实践是什么。 – e36M3

回答

0

我还没有找到任何有关最佳实践的信息,所以我会发布我的解决方案。我知道很多其他帖子都提到了这样一个事实,即EF上下文提供了查看它并查看特定实体是否处于附着状态的机制。因为我在存储库中工作(我的业务层没有直接访问EF上下文),我选择将这种逻辑卸载到存储库中,或者试图在业务层中解决它。我的感觉是,这个任务真的是一个商业问题,而不是数据访问层的问题。

Dictionary<string, Person> newPeople = ... 

foreach(row in fileRows) 
{ 
    Person person; 

    //if the person is already tracked by the dictionary, work with it, if not use the repository 
    if(!newPeople.TryGetValue(row.SSN, out person)) 
    { 
     person = personRepository.GetBySSN(row.SSN); 
    } 

    if(person == null) 
    { 
     //insert logic 

     //keep track that this person is already in line for inserting 
     newPeople.Add(row.SSN, person); 
    } 
    else 
    { 
     //update logic 
    } 
} 

personRepository.SaveChanges(); 
1

修改您的GetBySSN如下:

public Person GetBySSN(string ssn) 
{ 
    Person p = context.ObjectStateManager 
         .GetObjectStateEntries(~EntityState.Deleted) 
         .Where(e => !e.IsRelationship) 
         .Select(e => e.Entity) 
         .OfType<Person>() 
         .SingleOrDefault(p => p.SSN = ssn); 

    if (p == null) 
    { 
     p = context.People.SingleOrDefault(p => p.SSN = ssn); 
    } 

    return p; 
} 
+0

谢谢拉迪斯拉夫。这当然是另一种解决方法。如果你看看我上面的解决方案,我可以通过跟踪已经添加的内容来执行业务逻辑。 – e36M3

8

我想我可以给我给here

要坚持你通常将它添加到它的背景下DbSet实体相同的答案。

例如

var bar = new Bar(); 
bar.Name = "foo"; 
var context = new Context(); 
context.Bars.Add(bar); 

出人意料的是,查询context.Bars,刚添加的实体无法找到

var howMany = context.Bars.Count(b => b.Name == "foo"); 
// howMany == 0 

context.SaveChanges()之后,同一行会导致1

DbSet似乎没有意识到的变化直到他们坚持数据库。

幸运的是,每个DbSetLocal财产,它如同DbSet本身,但它反映了内存中的所有操作

var howMany = context.Bars.Local.Count(b => b.Name == "foo"); 
// howMany == 1 

您还可以使用Local添加实体

context.Bars.Local.Add(bar); 

和摆脱Entity Framework的怪异行为。

+0

因此,如果我想要未保存和保存的实体的'计数',我将不得不执行'context.Bars.Count + context.Bars.Local.Count'? –

+0

@RuudLenders否,context.Bars.Local应包含未保存的实体以及已存在于数据库中的实体。 – Hinek

+0

我必须纠正自己:只要你至少查询过一次context.Bars,context.Bars.Local就包含这两个参数。所以你不应该依赖context.Bars.Local来获得所有的数据,但是你不能只总结那两个Counts。 – Hinek

0

如果你想要去的拉吉斯拉夫的路线和查询ObjectStateManager那么你不妨使用扩展方法如下所示:

public static IEnumerable<TEntity> LoadedEntities<TEntity>(this ObjectContext Context) 
{ 
    return Context.ObjectStateManager 
     .GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged) 
     .Where(e => !e.IsRelationship).Select(e => e.Entity).OfType<TEntity>(); 
} 

这将让你那么做这样的事情:

Person p = context.LoadedEntities<Person>().SingleOrDefault(p => p.SSN = ssn); 
if (p != null) 
    return p; 
return context.People.SingleOrDefault(p => p.SSN = ssn); 
相关问题