2012-09-14 70 views
3

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

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

感谢

+0

基本上试图匹配自定义值而不是id /主键值。想知道是否有这样的配置设置 – JeremyBeadle

+0

这表面上看起来是一个数据库规范化步骤,其中有一个语言对象表,并且使用该语言对象的任何数据插入仅使用语言对象表键作为外键。你能否创建一种散列来唯一标识每个不同的可能语言对象,然后在将新的语言对象插入到语言对象表中时使用散列,并在插入其他数据时使用语言对象散列? –

+0

你知道语言代码吗?语言代码是语言实体上的关键字,还是相关实体的外键? – Pawel

回答

3

两个ObjectContextDbContext有试图找到在内存上下文已加载的实体法 - GetObjectByKeyObjectContextFindDbContext。使用这些方法可以避免从数据库中多次加载一个Language实体。

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

,指的您的评论...

本质上试图匹配的自定义值,而不是 ID /主键值。

...您不能使用这些方法,因为它们依赖于知道要查找的主键值。

我会做的是通过您自己的字典来模拟所提到的内部字典的逻辑,它将您的“自定义值”与实体而不是主键相关联。我假定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(); 
} 

这将只为每个LanguageCustomValue加载一个Language实体,只做一次,并且不会在数据库中创建Language对象的重复项。

1

不确定你在这里的意思,但如果在插入过程中,你通常会检查它是否存在,如果没有,就添加它。如果插入一堆实体,则可以将语言存储在上下文中。不知道这是否是最好的解决方案。不要以为没有快捷方式就可以在商店或上下文中找到没有密钥的对象。根据您语言实体的复杂性,您可以在 ToDictionary()之下投射上下文“语言”变量,然后转而使用它。

//'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(); 
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; 
} 

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

使用这种方法的好处:

  • 你只需要一次查询数据库的语言。列表填充后,它将被存储在内存中,这在性能方面更好。
  • 如果实体出现意外或错误的语言设置,您将能够使用默认语言。
+0

脚注:步骤2.1:可将foreach循环缩短为'lang_list = db.Languages.ToDictionary(row => row.Language,row => row.Id);'但这有点难以理解,所以我选择最可读的版本。 – Flater