Chr*_*ris 5 c# linq entity-framework
我的代码有问题,我尝试在两个对象之间保存多对多的连接,但由于某种原因它不会被保存.
我们使用代码优先方法来创建我们的数据库,在我们的数据库中我们有以下实体来解决这个问题:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductTag> ProductTags { get; set; }
}
public class ProductTag
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
ProductTagProducts表是自动创建的,当然这只是两者之间的连接表.
现在创建产品很好.我们可以运行以下命令,它将在ProductTagProducts表中创建连接:
Product.ProductTags.Add(productTag);
Run Code Online (Sandbox Code Playgroud)
为了确保数据库中没有重复的任务,我们自己处理它的保存.productTag始终包含具有现有ID的产品标签.
当我们想要编辑相同或其他产品时会出现问题.该产品有现有标签.我们使用以下过程来保存它:
List<ProductTag> productTags = new List<ProductTag>();
string[] splittedTags = productLanguagePost.TagList.Split(',');
foreach (string tag in splittedTags) {
ProductTag productTag = new ProductTag();
productTag.Name = tag;
productTags.Add(productTagRepository.InsertAndOrUse(productTag));
}
Run Code Online (Sandbox Code Playgroud)
我们用逗号分隔标记,这是从HTML元素接收的方式.然后我们为它定义一个新实体,并使用InsertAndOrUse来确定标签是否已经存在.如果标记已经存在,则返回相同的实体,但填写了ID,如果它不存在,则将标记添加到数据库,然后还返回具有ID的实体.我们创建了一个新列表,以确保产品中没有重复的Id(我已尝试将其直接添加到产品的现有标签列表中,结果相同).
product.ProductTags = productTags;
productRepository.InsertOrUpdate(product);
productRepository.Save();
Run Code Online (Sandbox Code Playgroud)
然后我们将列表设置为ProductTags并让存储库处理插入或更新,当然,将进行更新.以防万一,这是InsertOrUpdate函数:
public void InsertOrUpdate(Product product) {
if (product.Id == default(int)) {
context.Products.Add(product);
} else {
context.Entry(product).State = EntityState.Modified;
}
}
Run Code Online (Sandbox Code Playgroud)
save方法只调用上下文的SaveChanges方法.当我编辑产品并添加另一个标签时,它不会保存新标签.但是,当我在保存功能上设置断点时,我可以看到它们都在那里:
当我打开新添加的标签'Oeh-la-la'时,我甚至可以通过它返回产品:
但是当保存发生时,所有其他值都成功,则ProductTagProducts表中没有连接.也许这是非常简单的事情,但此刻我一无所知.我真的希望别人可以给人一种好看的感觉.
提前致谢.
编辑:请求ProductTag的InsertAndOrUse方法.它调用的InsertOrUpdate方法与上面完全相同.
public ProductTag InsertAndOrUse(ProductTag productTag)
{
ProductTag resultingdProductTag = context.ProductTags.FirstOrDefault(t => t.Name.ToLower() == productTag.Name.ToLower());
if (resultingdProductTag != null)
{
return resultingdProductTag;
}
else
{
this.InsertOrUpdate(productTag);
this.Save();
return productTag;
}
}
Run Code Online (Sandbox Code Playgroud)
你必须知道这条线......
context.Entry(product).State = EntityState.Modified;
Run Code Online (Sandbox Code Playgroud)
......对关系的状态没有影响.它只是标志着实体product
被传递到Entry
作为Modified
,即标量属性Product.Name
的修改,并没有其他标记.UPDATE
发送到数据库的SQL 语句只更新Name
属性.它不会在多对多链接表中写入任何内容.
您可以更改与该行的关系的唯一情况是外键关联,即在模型中将外键公开为属性的关联.
现在,多对多关系永远不是外键关联,因为您不能在模型中公开外键,因为外键位于模型中没有相应实体的链接表中.多对多关系始终是独立的关联.
除了对关系状态条目的直接操作(相当高级并且需要向下ObjectContext
)之外,只能使用实体框架的更改跟踪来添加或删除独立关联.此外,您必须考虑用户可能已删除标记,这要求必须删除链接表中的关系条目.要跟踪此类更改,您必须首先从数据库加载给定产品的所有现有相关标记.
要将所有这些组合在一起,您将不得不更改InsertOrUpdate
方法(或引入新的专用方法):
public void InsertOrUpdate(Product product) {
if (product.Id == default(int)) {
context.Products.Add(product);
} else {
var productInDb = context.Products.Include(p => p.ProductTags)
.SingleOrDefault(p => p.Id == product.Id);
if (productInDb != null) {
// To take changes of scalar properties like Name into account...
context.Entry(productInDb).CurrentValues.SetValues(product);
// Delete relationship
foreach (var tagInDb in productInDb.ProductTags.ToList())
if (!product.ProductTags.Any(t => t.Id == tagInDb.Id))
productInDb.ProductTags.Remove(tagInDb);
// Add relationship
foreach (var tag in product.ProductTags)
if (!productInDb.ProductTags.Any(t => t.Id == tag.Id)) {
var tagInDb = context.ProductTags.Find(tag.Id);
if (tagInDb != null)
productInDb.ProductTags.Add(tagInDb);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我Find
在上面的代码中使用,因为InsertAndOrUse
如果product.ProductTags
集合中的标签是否附加到context
实例,我不确定您的代码片段(缺少确切的代码).通过使用Find
它应该工作,无论它们是否被附加,可能以数据库往返为代价来加载标记.
如果product.ProductTags
附加了所有标签,您可以替换...
var tagInDb = context.ProductTags.Find(tag.Id);
if (tagInDb != null)
productInDb.ProductTags.Add(tagInDb);
Run Code Online (Sandbox Code Playgroud)
......只是
productInDb.ProductTags.Add(tag);
Run Code Online (Sandbox Code Playgroud)
或者如果不能保证它们全部附加并且您想避免往返数据库(因为您确定标记至少存在于数据库中,如果附加或不连接),您可以用以下代码替换代码:
var tagInDb = context.ProductTags.Local
.SingleOrDefault(t => t.Id == tag.Id);
if (tagInDb == null) {
tagInDb = tag;
context.ProductTags.Attach(tagInDb);
}
productInDb.ProductTags.Add(tagInDb);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
244 次 |
最近记录: |