我想创建一个表,其中数据唯一性基于多个列(2或3),但其中一列可以为null。 例如:
FRUIT WEIGHT UNIT
Apple
Apple 1 Kg
Apple 2 Kg
Orange
Orange 1 Kg
Orange 2 Kg
将全部视为唯一条目。 可以使用EF 6.1数据注释完成吗? 我相信我实现了这样:
[Required]
[Index("UniqueIndx", 1)]
public string Name { get; set; }
[Index("UniqueIndx", 2)]
public float? Weight { get; set; }
[Index("UniqueIndx", 3, IsUnique = true)]
public FormulUnit? Unit { get; set; }
产生:
public override void Up()
{
AlterColumn("MyDb.Fruits", "Weight", c => c.Single());
AlterColumn("MyDb.Fruits", "Unit", c => c.Int());
CreateIndex("MyDb.Fruits", new[] { "Name", "Weight", "Unit" },
unique: true, name: "UniqueIndx");
}
根据我对迁移创建的Up方法的理解,唯一性基于所有3列,而不仅仅是我编写该注释的最后一列。这对我来说没问题,这实际上就是我想要的。
我仍然有播种该表的问题。我在AddOrUpdate方法上遇到错误,如:
System.InvalidOperationException: The binary operator Equal is not defined for the types 'System.Nullable`1[System.Single]' and 'System.Single'.
有:
context.Fruits.AddOrUpdate(
p => new {p.Name, p.Weight, p.Unit}, fr1, fr2, fr3
);
我错过了什么吗? 感谢
答案 0 :(得分:1)
我刚刚调试了EF source code
,抛出错误的代码位于AddOrUpdate
内。
以下是导致错误的代码摘录的一部分。
var matchExpression
= identifyingProperties.Select(
pi => Expression.Equal(
Expression.Property(parameter, pi.Single()),
Expression.Constant(pi.Last().GetValue(entity, null))))
或者你可以通过这样做来复制错误。
var fr1 = new Fruit { Weight = 1 };
var epe = Expression.Property(Expression.Constant(fr1), "Weight");
var ec = Expression.Constant(fr1.Weight);
var ee = Expression.Equal(epe, ec);
我不确定为什么Float?
不被Expression.Equal
接受,也许其他人可以解释。
但是,如果您可以使用Add
或手动检查是否添加或更新,而不是AddOrUpdate
,那将会有效。
答案 1 :(得分:0)
更新2:
以下是我认为我的错误,并给出了可能的解决方案。但后来我又错了。虽然下面的代码使用基于3个条件的索引向数据库添加新记录,因为它在进程期间创建了匿名类型的新对象,但是松散了外键关系。 如果你有一个父类,我们称之为拥有许多Fruit的Grocery,种子方法不会用以下给定代码更新这些关系。
回到工作岗位......
我的逻辑错了。
如果我们有基于多个条件的唯一索引,那么如何判断要更新的记录?一个具有三个不同标准的记录可能是一个很好的新记录,或者它可能是一个旧的更新,但这不是编译器可以告诉的。
每条记录都需要手动添加。
谢谢Yuliam。
<强>更新强> 对于那些陷入同样困境的人来说,这就是我如何解决这种情况(借助其他Stackoverflow帖子)
首先,你必须知道Fruit实体有一个带ID的基本实体,这就是你在这里看不到它的原因。 然后,为了更好地理解这里需要采取的步骤:
将所有这些新对象添加到上下文(然后是context.save())
var SeedFruits = new List {fr1,fr2,fr3};
var result = from in context.Fruits 选择新的{a.Name,a.Weight,a.Unit};
列出DBFruitsList = result.AsEnumerable() 。选择(o =&gt;新水果 { 名称= o.Name, 重量= o。重量, 单位= o.Unit })ToList();
var UniqueFruitsList = 来自SeedFruits的ai where!DBFruitsList.Any(x =&gt; x.Name == ai.Name&amp;&amp; x.Weight == ai.Weight&amp;&amp; x.Unit == ai.Unit) 选择ai;
foreach(UniqueFruitsList中的Fruit fruittoupdate) { context.Fruits.Add(fruittoupdate); }