实体框架 - 使用DatabaseGeneratedOption.None保存/更新多对多 [英] Entity Framework - saving/updating many to many with DatabaseGeneratedOption.None

查看:223
本文介绍了实体框架 - 使用DatabaseGeneratedOption.None保存/更新多对多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

各位大家好!
$


我有一个使用以下模型与多对多关系的应用程序;使用Code-First方法是EF:

Hello everyone!

I have an app that uses following model with many-to-many relationship; it is EF with Code-First approach:

public class UserContext : DbContext
    {
        public UserContext() : base("Name=myDB")
        { }    
        public DbSet<JobData> Jobs { get; set; }
        public DbSet<TaskInfo> TaskInfos { get; set; }
    }
 
 public class JobData
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)] 
        public int JobDataId { get; set; }            
...
        public virtual ICollection<TaskInfo> TaskInfoes { get; set; }
}
  public class TaskInfo
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int TaskInfoId { get; set; }
public int ImportantDataId {get; set;} 
...
 public virtual ICollection<JobData> JobDatas { get; set; }
}

DatabaseGeneratedOption.None对我来说非常重要,因为我想避免任何重复的实例。更确切地说:我的应用程序从外部存储获取JobData实例并将其放入myDB。这些JobData附带了一些TaskInfoes。我的
键是JobDataId& TaskInfoId - 我手动设置它们(实际上当我从外部源抓取这些实例时,它们已经带有Ids,我只是确保它们被分配)。这样做:如果获得JobData或TaskInfo和myDB已经
具有相同Id的实体,那么我不应该盲目地添加新数据,而是更新现有数据。 

DatabaseGeneratedOption.None is extemely important for me here, since I want to avoid any duplicate instances. To be more exact: my app gets JobData instances from external storage and puts it into myDB. These JobData come along with some TaskInfoes. My keys are JobDataId & TaskInfoId - i'm setting them manually (actually when I'm grabbing these instances from external source they come with Ids already, I just make sure they are assigned). It is done to: if'm getting JobData or TaskInfo and myDB already has the entity with the same Id, then I shouldn't just blindlessly add new data, but update existing. 

当我用一组TaskInfoes保存/更新单个JobData时,一切正常。

Everything works fine, when I'm saving/updating single JobData with set of TaskInfoes.

但是,假设我有JobData id ==#333并且它有一些TaskInfoes 带有ID(#14,#15,#16,#17,#18) - 它已存储在myDB中。 



然后,我从外部存储器获取另一个JobData实例,假设id ==#500,这个新的JobData实例作为一些具有与myDB相同的ID的任务。例如,它收集了带有ID的TaskInfoes(#14,#15,#25,#27)。



我需要的是:


1。保存此新JobData实例

2。对于myDB和此JobData中的每个任务(#14,#15) - 使用新获取的信息(例如taskInDB.ImportantDataId = taskFromExternalStorage.ImportandDataId)更新这些任务并保存它们。他们应该为JobDatas
(#333,#500)提供参考。 


3.对于未在DB中显示的所有其他任务 - 只需保存他们

However, suppose, I have JobData with id == #333 and it has some TaskInfoes  with ids  (#14, #15, #16, #17, #18) - and it is already stored in myDB. 

Then, I'm getting another instance of JobData from external storage , let's say with id == #500, and this new JobData instance  as some tasks with the same ids as in myDB. For example, it has colletion of TaskInfoes with ids (#14,#15, #25, #27).

What I need here is:

1. Save this new JobData instance
2. For each task that is in myDB and in this JobData (#14,#15) - update these tasks with newly gotten information (e.g. taskInDB.ImportantDataId = taskFromExternalStorage.ImportandDataId) and save them. They should hold references for both JobDatas (#333, #500). 
3.For all other tasks that were not presented in DB - just save them

我一直在尝试这样做:

I've been trying to do something like this:

public void InsertOrUpdateItem(JobData item)
       {
           foreach (var task in item.TaskInfoes)
           {
               var taskInDB = context.TaskInfos.SingleOrDefault(tk => tk.TaskInfoId == task.TaskInfoId);
               if (taskInDB != null)
               {
                   taskInDB.Property= task.Property;                  
               }
               else
               {
                   context.TaskInfos.Add(task);
               }
           }
           var jobC = context.Jobs.SingleOrDefault(job => job.JobDataId == item.JobDataId);
           if (jobC != null)
           {
               context.Entry(item).State = EntityState.Modified;
           }
           else
           {
               context.Jobs.Add(item); //here is what my be causing problems
           }
       }
... //and after that I am calling
context.SaveChanges()

我在"SaveChanges()"上遇到重复的密钥插入异常打电话,这在这里很合乎逻辑。 EF尝试插入新数据而不是更新。我如何设法做到这一切? 

I'm getting a duplicate key insert exception on "SaveChanges()" call, which is quite logical here. EF tries to insert new data instead of updating. How do I manage to do all this? 

推荐答案

AddOrUpdate
方法 在调用SaveChanges时按键添加或更新实体。相当于"upsert"。数据库术语的操作。

AddOrUpdate method adds or updates entities by key when SaveChanges is called. Equivalent to an "upsert" operation from database terminology.

请尝试以下代码:

context.Jobs.AddOrUpdate(job => job.JobDataId, item);
context.SaveChanges();

同时检查此主题:
更新行如果它存在其他插入逻辑与实体框架

< a href ="https://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager(v=vs.110).aspx#Examples\"target ="_ blank"> ObjectStateManager   class 允许您检查实体类型实例和关系
实例的对象状态和身份管理,有几种不同的方法可以使用它。

ObjectStateManager class allow you check object state and identity management for entity type instances and relationship instances, there are several different ways to use it.

并检查此主题:
EntityFramework,如果不存在则插入,否则更新

您可以直接查看现有记录,如下所示:

You can check exist record straightforward as below:

var query = db.Jobs
                .Where(job => job.JobDataId== item.Id) 
                .SingleOrDefault();
            if (query != null)
                db.Jobs.ApplyCurrentValues(item);
            else
                db.Jobs.AddObject(item);

如果我有任何误解,你还可以为其他任何人提供所有必要的代码片段能够从头开始重现您的问题以及有关结果的详细说明,包括任何异常消息。

If I have any misunderstanding, you can also include all necessary code snippets for anyone else to be able to reproduce your issue from scratch along with a detailed description about the results including any exception messages.

最好的问候,

Bob


这篇关于实体框架 - 使用DatabaseGeneratedOption.None保存/更新多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆