更新:最近我得到了一些赞,所以我想让人们知道我下面给出的建议并不是最好的。自从我最初开始在旧的无键数据库上做实体框架,我已经意识到,到目前为止,你能做的最好的事情是先反向编码。有一些关于如何做到这一点的好文章。只需遵循它们,然后当您想要向它添加一个键时,使用数据注释来“伪造”键。
例如,假设我知道我的Orders表,虽然它没有主键,但可以保证每个客户只有一个订单号。由于这是表上的前两列,我将代码第一个类设置为如下所示:
[Key, Column(Order = 0)]
public Int32? OrderNumber { get; set; }
[Key, Column(Order = 1)]
public String Customer { get; set; }
通过这样做,您基本上伪造了EF,使其相信存在一个由OrderNumber和Customer组成的聚集键。这将允许您在无键表上进行插入、更新等操作。
如果你不太熟悉反向代码优先,去找一个关于实体框架代码优先的好教程。然后在“反向编码优先”(即使用现有数据库进行“编码优先”)上找到一个。然后回到这里,再看看我的主要建议。:)
最初的回答:
首先:正如其他人所说,最好的选择是向表添加一个主键。句号。如果你能做到这一点,就不要再读下去了。
但如果你做不到,或者讨厌自己,也有一种不用主键的方法。
在我的例子中,我使用的是遗留系统(最初是AS400上的平面文件移植到Access,然后移植到T-SQL)。所以我必须想办法。这就是我的解。我使用Entity Framework 6.0(在撰写本文时,NuGet的最新版本)完成了以下工作。
Right-click on your .edmx file in the Solution Explorer. Choose "Open With..." and then select "XML (Text) Editor". We're going to be hand-editing the auto-generated code here.
Look for a line like this:
<EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">
Remove store:Name="table_name" from the end.
Change store:Schema="whatever" to Schema="whatever"
Look below that line and find the <DefiningQuery> tag. It will have a big ol' select statement in it. Remove the tag and it's contents.
Now your line should look something like this:
<EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />
We have something else to change. Go through your file and find this:
<EntityType Name="table_name">
Nearby you'll probably see some commented text warning you that it didn't have a primary key identified, so the key has been inferred and the definition is a read-only table/view. You can leave it or delete it. I deleted it.
Below is the <Key> tag. This is what Entity Framework is going to use to do insert/update/deletes. SO MAKE SURE YOU DO THIS RIGHT. The property (or properties) in that tag need to indicate a uniquely identifiable row. For instance, let's say I know my table orders, while it doesn't have a primary key, is assured to only ever have one order number per customer.
我的是这样的:
<EntityType Name="table_name">
<Key>
<PropertyRef Name="order_numbers" />
<PropertyRef Name="customer_name" />
</Key>
说真的,别做错了。让我们假设,尽管不应该有重复的数据,但由于某种原因,有两行数据进入了我的系统,它们具有相同的订单号和客户名称。Whooops !这就是我不用钥匙的后果!所以我使用实体框架删除一个。因为我知道副本是今天唯一的订单,我这样做:
var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);
你猜怎么着?我刚刚删除了副本和原件!这是因为我告诉实体框架order_number/ customer_name是我的主键。所以当我告诉它删除duplicateOrder时,它在后台做的事情是这样的:
DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)
有了这个警告……您现在应该可以开始了!