[英]Entity Framework 4 TPH inheritance, how to change one type into another?
我已經找到了一些有關這方面的信息,但還不足以讓我理解這種情況的最佳實踐。 我有你的典型TPH設置與抽象基類“公司”。 我有幾個孩子“小公司”,“大公司”等繼承自公司。 實際上,我實際上對公司有不同的現實分類,但我試圖在這個例子中保持簡單。 在根據TPH的數據庫中,我有一個具有FirmTypeId列(int)的Firm表,用於區分所有這些類型。 一切都很好,除了我要求允許用戶將一種類型的公司改為另一種。 例如,用戶在添加公司時可能會犯錯,並希望將其從Big Firm更改為Small Firm。 因為實體框架不允許將區分數據庫列暴露為屬性,所以我不相信有一種方法可以通過EF將一種類型更改為另一種類型。 如果我錯了,請糾正我。 我看到它的方式我有兩個選擇:
我看過一篇文章,人們認為OOP的一個原則是實例不能改變它們的類型。 雖然這對我來說很有意義,但我似乎無法連接點。 如果我們遵循這個規則,那么唯一一次使用任何類型的繼承(TPH / TPT)就是確定一種類型永遠不會轉換為另一種類型。 因此,小公司永遠不會成為一家大公司。 我看到應該使用構圖的建議。 即使它對我來說沒有意義(意思是我沒有看到公司如何擁有一家大公司,對我來說,一家大公司就是一家公司),我可以看到如果數據存在,如何在EF中建模組合。多個表。 但是,在我在數據庫中有一個表的情況下,它似乎是TPH或我在上面#1和#2中描述的內容。
我在我們的項目中遇到了這個問題,我們有核心DBContext
和一些帶有自己DBContexts
“可插拔”模塊,其中“模塊用戶”繼承了“核心(基礎)用戶”。 希望這是可以理解的。
我們還需要改變(我們稱之為)的能力, User
對Customer
(如果需要還的另一個“繼承” Users
在同一時間,使用戶可以使用所有這些模塊。
因為我們嘗試使用TPT繼承,而不是TPH - 但TPH也會以某種方式工作。
一種方法是使用許多人建議的自定義存儲過程 ...
我想到的另一種方法是向DB發送自定義插入/更新查詢 。 在TPT中它將是:
private static bool UserToCustomer(User u, Customer c)
{
try
{
string sqlcommand = "INSERT INTO [dbo].[Customers] ([Id], [Email]) VALUES (" + u.Id + ", '" + c.Email + "')";
var sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["DBContext"].ConnectionString);
sqlconn.Open();
var sql = new SqlCommand(sqlcommand, sqlconn);
var rows = sql.ExecuteNonQuery();
sqlconn.Close();
return rows == 1;
}
catch (Exception)
{
return false;
}
}
在此方案中, Customer
繼承User
並且只有string Email
。
使用TPH時 ,查詢只會從INSERT ... VALUES ...
更改為UPDATE ... SET ... WHERE [Id] = ...
別忘了改變Discriminator
專欄。
下次調用dbcontext.Users.OfType<Customer>
,我們的原始用戶“轉換”為客戶。
底線:我還嘗試了另一個問題的解決方案,其中包括從ObjectStateManager
分離原始實體(用戶)並修改新的實體(客戶)狀態,然后保存dbcontext.SaveChanges()
。 這對我沒用(TPH和TPT都沒有)。 因為每個模塊使用單獨的DBContexts,或者因為EntityFramework 6(.1)忽略了這一點。 在這里能找到它。
是的,你做得很好。 EF繼承不支持此方案。 更改現有公司的公司類型的最佳方法是使用存儲過程。
請查看這篇文章了解更多信息:
在實體框架中更改繼承的類型
除非您明確要使用關系繼承的多態功能,否則為什么不查看拆分策略?
編輯:APOLOGIES,這是EF 6.x答案
我發布了完整性的示例代碼。 在這種情況下,我有一個基礎Thing
類。 然后,子類: ActiveThing
和DeletedThing
我的OData ThingsController
有一個主要的GetThings
,我打算只公開ActiveThing
,但是,它的GetThing(ThingId)仍然可以返回任何類型的對象。 Delete
操作以OP請求的方式執行從ActiveThing
到DeletedThing
的轉換,並且以其他答案中描述的方式執行。 我正在使用內聯SQL(參數化)
public class myDbModel:DbContext
{
public myDbModel(): base("name=ThingDb"){}
public DbSet<Thing> Things { get; set; } //db table
public DbSet<ActiveThing> ActiveThings { get; set; } // now my ThingsController 'GetThings' pulls from this
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//TPH (table-per-hierarchy):
modelBuilder.Entity<Ross.Biz.ThingStatusLocation.Thing>()
.Map<Ross.Biz.ThingStatusLocation.ActiveThing>(thg => thg.Requires("Discriminator").HasValue("A"))
.Map<Ross.Biz.ThingStatusLocation.DeletedThing>(thg => thg.Requires("Discriminator").HasValue("D"));
}
}
這是我更新的ThingsController.cs
public class ThingsController : ODataController
{
private myDbModel db = new myDbModel();
/// <summary>
/// Only exposes ActiveThings (not DeletedThings)
/// </summary>
/// <returns></returns>
[EnableQuery]
public IQueryable<Thing> GetThings()
{
return db.ActiveThings;
}
public async Task<IHttpActionResult> Delete([FromODataUri] long key)
{
using (var context = new myDbModel())
{
using (var transaction = context.Database.BeginTransaction())
{
Thing thing = await db.Things.FindAsync(key);
if (thing == null || thing is DeletedThing) // love the simple expressiveness here
{
return NotFound();//was already deleted previously, so return NotFound status code
}
//soft delete: converts ActiveThing to DeletedThing via direct query to DB
context.Database.ExecuteSqlCommand(
"UPDATE Things SET Discriminator='D', DeletedOn=@NowDate WHERE Id=@ThingId",
new SqlParameter("@ThingId", key),
new SqlParameter("@NowDate", DateTimeOffset.Now)
);
context.ThingTransactionHistory.Add(new Ross.Biz.ThingStatusLocation.ThingTransactionHistory
{
ThingId = thing.Id,
TransactionTime = DateTimeOffset.Now,
TransactionCode = "DEL",
UpdateUser = User.Identity.Name,
UpdateValue = "MARKED DELETED"
});
context.SaveChanges();
transaction.Commit();
}
}
return StatusCode(HttpStatusCode.NoContent);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.