物件
public class Noun
{
public int Id { get; set; }
[MaxLength(128)]
public string Name { get; set; }
public bool Active { get; set; }
public virtual Category Category { get; set; }
public int CategoryId { get; set; }
}
public class Category
{
public int Id { get; set; }
[MaxLength(128)]
public string Name { get; set; }
}
存储库
public Noun CreateNoun(string name, string categoryName)
{
using (MyContext context = new MyContext())
{
Noun noun;
Category category;
lock (NounLock)
{
// don't create it if it already exists
noun = context.Nouns
.Include(t => t.Category)
.FirstOrDefault(t => t.Name == name && t.Category.Name == categoryName);
if (noun == null)
{
// make the category if it doesn't already exist
lock (CategoryLock)
{
category = context.Categories.FirstOrDefault(c => c.Name == categoryName);
if (category == null)
{
category = new Category() { Name = categoryName };
context.Categories.Add(category);
context.SaveChanges();
}
}
noun = new Noun()
{
Name = name,
Category = category,
CategoryId = category.Id
};
context.Nouns.Add(noun);
}
else
{
category = noun.Category;
}
// make sure the noun is set as active
noun.Active = true;
context.Entry(category).State = EntityState.Unchanged;
context.SaveChanges();
return noun;
}
}
}
上下文
internal class MyContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Noun> Nouns { get; set; }
public MyContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Nouns
modelBuilder.Entity<Noun>()
.HasRequired(t => t.Category);
}
}
问题
当调用CreateNoun()时,当具有该类别的名词已经存在时,它应该(基于我认为我在做什么),只需从数据库加载现有的名词并将其标记为活动。但相反,它会插入一个新的名词和一个新的类别。我究竟做错了什么?我知道这可能是一件小事。
PS:锁是静态的,因为这可能被多线程租户使用
示例
Noun newNoun = repo.CreateNoun("name", "cat");
// should load existing noun from db, and set it as active, but instead duplicates it
Noun oldNoun = repo.CreateNoun("name", "cat");
答案 0 :(得分:1)
CreateNoun
方法中存在一些问题,我做了一些我稍后要解释的更改:
public Noun CreateNoun(string name, string categoryName)
{
using (MyContext context = new MyContext())
{
Noun noun;
Category category;
lock (NounLock)
{
// don't create it if it already exists
noun = context.Nouns
.FirstOrDefault(t => t.Name == name && t.Category.Name == categoryName);
if (noun == null)
{
// make the category if it doesn't already exist
lock (CategoryLock)
{
category = context.Categories.FirstOrDefault(c => c.Name == categoryName);
if (category == null)
{
category = new Category() { Name = categoryName };
context.Categories.Add(category);
}
}
noun = new Noun()
{
Name = name,
Category = category,
};
context.Nouns.Add(noun);
}
// make sure the noun is set as active
noun.Active = true;
context.SaveChanges();
return noun;
}
}
}
Include
,EF会加载类别
物业给你。这个navegation属性是虚拟的,它将是
lazy loaded。Category
时,您不需要致电
SaveChanges
方法。在回到noum之前,你是在呼唤这个
方法,它将保存您之前所做的所有更改。CategoryId
。你不知道
如果category
是从DB加载的或最近创建的。只需设置
navegation property Category
。Category
州另一个推荐:
在OnModelCreating
方法中,您根据需要配置Category
。当您要配置关系时,使用方法HasRequired
。在你的情况下,它将是这样的:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Noun>()
.HasRequired(t => t.Category).WithMany().HasForeignKey(n=>n.CategoryId);
}
正如@Shoe在关于第一点的评论中所说,如果你想使用此方法返回的Noun
并查阅其类别,请在搜索{时调用Include
方法{1}}正如您之前所做的那样。
答案 1 :(得分:0)
您尚未在模型中标记您的钥匙。两个Id
属性都需要标有[Key]
,而Category
类中的Noun
属性需要[ForeignKey("CategoryId")]
注释。由于t.Category.Name
始终为空,因此重复检查始终失败。