实体框架,自动链接到插入的现有实体

时间:2012-09-14 12:48:42

标签: entity-framework

我不确定这是否可行但是我在数据库中插入了很多实体,并且对于每个项目它都说一个语言属性是一个实体。目前,我为每个正在插入的项目创建了一个新的语言对象,但这仅用于测试,因为它会创建大量重复项。这些语言在数据库中应该是唯一的,并且应该指向现有的语言记录,我能想到的唯一方法是对每个插入进行单独的服务调用以查找语言代码并获得现有语言的id,即很多开销。

有没有办法让它根据语言代码自动查找记录并使用该记录?

由于

3 个答案:

答案 0 :(得分:3)

ObjectContextDbContext都有尝试从内存中的上下文中查找已加载实体的方法 - GetObjectByKey ObjectContextFind { {1}}。使用这些方法可以避免从数据库中多次加载DbContext实体。

两种方法都需要主键值作为输入参数来按键查找实体。基本上将这些方法视为访问将主键与实体对象相关联的内部字典。

现在,请参阅您的评论......

  

基本上尝试匹配自定义值而不是   id /主键值。

...您无法使用这些方法,因为它们依赖于了解您要查找的主键值。

我要做的是通过您自己的字典来模仿所提及的内部字典的逻辑,该字典将您的“自定义值”与实体而不是主键相关联。我假设自定义值在Language表中是唯一的。

所以,这个想法将是:

鉴于你有这样的实体......

Language

...并且您有一组数据用于插入新实体...

public class MyEntity
{
    public int Id { get; set; }
    public Language Language { get; set; }
    public string SomeOtherValue { get; set; }
    // ... more
}

public class Language
{
    public int Id { get; set; }             // primary key value
    public string CustomValue { get; set; } // the unique custom value
    // ... more
}

...然后你可以用这个:

public class Data
{
    public string SomeOtherValue { get; set; }
    public string LanguageCustomValue { get; set; }
    // ... more
}

var dataList = new List<Data>
{
    new Data { SomeOtherValue = "A", LanguageCustomValue = "EN" },
    new Data { SomeOtherValue = "B", LanguageCustomValue = "FR" },
    new Data { SomeOtherValue = "C", LanguageCustomValue = "EN" },
    new Data { SomeOtherValue = "D", LanguageCustomValue = "EN" },
    // ... more
}

这将只为每个using (var context = new MyContext()) { var dict = new Dictionary<string, Language>(); foreach (var data in dataList) { Language language; if (!dict.TryGetValue(data.LanguageCustomValue, out language)) { // load the language only once from the database language = context.Languages.SingleOrDefault(l => l.CustomValue == data.LanguageCustomValue); dict.Add(data.LanguageCustomValue, language); } var myEntity = new MyEntity { SomeOtherValue = data.SomeOtherValue, Language = language }; context.MyEntities.Add(myEntity); // or AddObject } context.SaveChanges(); } 加载一个Language实体,只执行一次,并且不会在数据库中创建LanguageCustomValue个对象的副本。

答案 1 :(得分:1)

不确定这里的确切含义,但如果它在插入过程中,您通常会检查它是否存在,如果不存在则添加它。如果插入一堆实体,可以将语言存储在上下文中。不确定这是否是最好的解决方案。不要以为没有密钥就可以快速找到商店或上下文中的对象。根据您的语言实体的复杂程度,您可以在 ToDictionary()下面转换上下文'languages'变量,然后翻阅它。

//'db' is your context here.
var languages = db.Languages.all();
myentity MyEntity = new MyEntity();
myentity.property1 = "mynewvalue1";

var newlang = new Language{ LanguageName= "newlanguagename"};
//language exists?
if (!languages.Any( u => u.LanguageName== newlang.LanguageName ))
 {

  // no:
  db.Languages.InsertOnSubmit(newlang);
  db.SubmitChanges();
  myentitly.Language = newlang;
 }
else{

  //yes:
  myentitly.Language = languages.Where( u => u.LanguageName== newlang.LanguageName).Single();
 }

db.MyEntities.InsertOnSubmit(myentity);
db.SubmitChanges();

答案 2 :(得分:1)

由于您担心开销性能成本,我建议将其作为处理此问题的最有效方法:

第1步:确保您的语言表格正确。

我不确定您如何定义使用哪种语言,所以我在这里无法帮助您,只需确保您的语言表包含所有需要的行。 我们假设您的表格如下:

{ Id: 1 ; Language: "English" }
{ Id: 2 ; Language: "French"  }
{ Id: 3 ; Language: "German"  }

第2步:处理您的实体

步骤2.1:创建Dictionary<string, int>以轻松映射语言表:

var lang_list = new Dictionary<string, int>();

using(var db = new DbContext()
{
     foreach(var row in db.Languages.ToList())
     {
            lang_list.Add(row.Language, row.Id);
     }
}

//From now on, you can refer to the local list.

步骤2.2:向(待添加)实体添加正确的语言

我不知道您将如何确定需要添加哪种语言。假设您有一个字符串变量myLanguage,其中包含您需要的语言的字符串名称。

你可能想要使用类似的东西:

int foundvalue;

if(lang_list.TryGetValue( myLanguage , out foundvalue ))
{
     //if language is in the list, the value (= the id of the row in the language
     // table) will be stored in foundvalue
     myEntity.LanguageId = foundvalue;
}
else
{
     //if the language wasn't found in the list, set a default lang (e.g. English)
     myEntity.LanguageId = 1;
}

我希望这可以帮助您解决问题吗?

使用此流程的好处:

  • 您只需要为语言查询一次数据库。填充列表后,它将存储在内存中,这是一种性能更好的方法。
  • 如果实体的语言设置意外或不正确,您将可以使用默认语言。