[英]Unable to determine the principal end of the etaxiDataModel relationship. Multiple added entities may have the same primary key
[英]Correct way of mapping a 'one to many' relationship. When having the same relation in multiple entities
假設類和關系的以下結構:
class Document
{
public List<Version> DocumentVersions { get; set; }
// Other properties
}
class Register
{
public List<Version> RegisterVersions { get; set; }
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}
使用EF Core時,它將分別產生3個表D,R和V,其中V將具有2個FK,一個用於D,一個用於R。
我的問題是:
也許值得一提的是,我的示例過於簡化,實際上我有6個實體使用相同的V實體。
我不認為這真的是一對多的關系,請看這里 。
如果(例如) Document
具有多個(例如,一個列表) Version
那將是一對多的關系。
如果希望多個實體引用相同的實體類型,則可以將外鍵明確地放置在Document
和Register
類中:
class Document
{
public Version DocumentVersion { get; set; }
public int DocumentVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Register
{
public Version RegisterVersion { get; set; }
public int RegisterVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}
因此,難題是:
A)我應該在Version
保留兩個FK還是
B)建立兩個表DocumentVersion
和RegisterVersion
而不是Version
?
好吧,事實是兩者都可以。 您只需要決定哪種方法更適合您的系統即可。 讓我們快速瀏覽。
方法A
回答你的問題; 是EF的默認方法是正確的。 在創建兩個FK和構建兩個表的過程中,它將創建兩個FK。 僅在用於多對多關系的中間表的情況下,它將創建一個額外的表。
不過,我始終建議我們自己創建所有FK,而不要讓EF為我們做。 這樣,我們就可以更好地控制關系的行為,並且還可以訪問應用程序中的FK,因為它們是實體的屬性。
public class Version
{
[Key]
public int VersionNumber { get; set; }
public int? DocumentID { get; set; }
public virtual Document Document { get; set; }
public int? RegisterID { get; set; }
public virtual Register Register { get; set; }
//Other properties
}
由於Version
具有PK,因此它可以創建記錄,而沒有任何FK具有任何值。 如果您的業務模型允許這樣做,請保持原樣。 您以后可以提供一個UI,以將“版本”分配給“文檔”或“注冊”。
如果要在“ Version
表中添加一些規則,請執行以下操作: 例如,每條記錄應至少具有一個FK或只有一個FK,您可以通過重寫DbContext
類的ValidateEntity
方法(或可能通過數據庫中的某些sql約束)來做到這一點。
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry, IDictionary<object, object> items)
{
// validate entity from annotations
var result = base.ValidateEntity(entityEntry, items);
// custom validation rules
if (entityEntry.Entity is Version &&
(entityEntry.State == EntityState.Added || entityEntry.State == EntityState.Modified))
{
Version version = ((Version)entityEntry.Entity);
if (version.DocumentID == null && version.RegisterID == null)
result.ValidationErrors.Add(new DbValidationError(null, "A document or register must be specified."));
}
return result;
}
請注意,您可以創建自己的注釋以驗證實體屬性。 但是這些僅限於單個屬性。 如果要添加組合多個屬性的ValidateEntity
, ValidateEntity
方法是我所知道的唯一方法。
方法B
有兩種方法可以實現此方法。 首先是保留Version
表,並在頂部添加兩個中間表。
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
public class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
public class RegisterVersion
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
實際上,這允許多對多關系,但是您可以將其用作一對多關系。 第二種方法是使Version
抽象(不是數據庫表)並構建兩個新表以從Version
繼承:
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
// don't make this a DbSet
public abstract class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion : Version
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
// other properties
}
public class RegisterVersion : Version
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }}
// other properties
}
這是一種正確而清晰的一對多關系。
結論底線是您可以使用兩種方法中的任何一種,並且可以進行更改以適合您的需求。
我已經成功使用了兩種方法,但是我傾向於使用第二種方法(以及抽象類繼承)。 第一種方法似乎更多地是減少數據庫資源或簡化開發的方法,但是現代數據庫根本沒有更多的壓力,並且開發可能變得不必要地復雜。 此外,第二種方法允許通過分別向每個連接表添加其他屬性來擴展關系的功能。 對於必須處理的6個實體,采用第二種方法對我來說似乎更安全。 我在具有許多文件類型和關系的應用程序中使用了這種方法,並且它總是非常簡單和可擴展的。 每個沖突表中的那些額外屬性也非常方便。
希望我能幫忙,祝您編程愉快!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.