多态性:ORM实体是域实体还是数据实体?

我有一个BankAccount表。 LINQ to SQL生成一个名为“BankAccount”的类,如下所示。

[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")] public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged 

现在,作为一个新手,我自己新创建域对象。 请参阅IBankAccount接口和FixedBankAccount类。 关键点在于存在多态行为–IBankAccount可以是FixedBankAccount或SavingsBankAccount。

对于这个例子的另一个问题,我有以下两条评论。

  1. @mouters:“你的存储库对象和域对象很奇怪 – 你的存储库是不是只返回域对象?”
  2. @SonOfPirate:“存储库应该使用工厂来根据从数据存储中检索的数据创建实例。”

质询

1)我手动创建域实体。 这是错误的方法吗? 如果是错的,LINQ to SQL类如何处理多态? 如何将方法添加到这些类?

2)存储库应如何使用工厂根据从数据存储中检索的数据创建实例? 任何代码示例或参考?

3)它是否满足单一责任原则?

 public interface IBankAccount { int BankAccountID { get; set; } double Balance { get; set; } string AccountStatus { get; set; } void FreezeAccount(); void AddInterest(); } public class FixedBankAccount : IBankAccount { public int BankAccountID { get; set; } public string AccountStatus { get; set; } public double Balance { get; set; } public void FreezeAccount() { AccountStatus = "Frozen"; } } public class BankAccountService { RepositoryLayer.IRepository accountRepository; ApplicationServiceForBank.IBankAccountFactory bankFactory; public BankAccountService(RepositoryLayer.IRepository repo, IBankAccountFactory bankFact) { accountRepository = repo; bankFactory = bankFact; } public void FreezeAllAccountsForUser(int userId) { IEnumerable accountsForUser = accountRepository.FindAll(p => p.BankUser.UserID == userId); foreach (RepositoryLayer.BankAccount oneOfRepositoryAccounts in accountsForUser) { DomainObjectsForBank.IBankAccount domainBankAccountObj = bankFactory.CreateAccount(oneOfRepositoryAccounts); if (domainBankAccountObj != null) { domainBankAccountObj.BankAccountID = oneOfRepositoryAccounts.BankAccountID; domainBankAccountObj.FreezeAccount(); this.accountRepository.UpdateChangesByAttach(oneOfRepositoryAccounts); oneOfRepositoryAccounts.Status = domainBankAccountObj.AccountStatus; this.accountRepository.SubmitChanges(); } } } } public interface IBankAccountFactory { DomainObjectsForBank.IBankAccount CreateAccount(RepositoryLayer.BankAccount repositoryAccount); } public class MySimpleBankAccountFactory : IBankAccountFactory { //Is it correct to accept repositry inside factory? public DomainObjectsForBank.IBankAccount CreateAccount(RepositoryLayer.BankAccount repositoryAccount) { DomainObjectsForBank.IBankAccount acc = null; if (String.Equals(repositoryAccount.AccountType, "Fixed")) { acc = new DomainObjectsForBank.FixedBankAccount(); } if (String.Equals(repositoryAccount.AccountType, "Savings")) { //acc = new DomainObjectsForBank.SavingsBankAccount(); } return acc; } } 

阅读

  1. 将Linq中的外键设置为SQL

  2. LINQ to SQL中的多态关联

  3. DTO(linq2sql)和Class对象之间的混淆!

  4. LINQ-to-XYZ多态性?

  1. 我不完全确定您对LINQ to SQL的要求,但手动创建域对象肯定不是错误的方法。 如果您依赖它们生成代码,则无法获得正确封装的域对象。
  2. 关于工厂模式,你已陷入困境。 正如mouters所指出的那样,你有两个代表相同事物的对象:

    RepositoryLayer.BankAccount

    DomainObjectsForBank.IBankAccount

只有在创建对象时需要“策略”时才需要工厂。 它们使用的经典案例是多态和inheritance。 您的帐户类有子类,因此有一个AccountFactory的案例。 但是,如果你有复杂的情况,那就是让存储库返回某种帐户数据对象,然后将其传递给工厂以将其转换为正确的子类域对象。 相反,存储库应该从数据库获取数据,将其传递给工厂,然后从工厂返回创建的域对象。 例如:

 public class AccountRepository : IAccountRepository { public Account GetById(Guid id) { using (AccountContext ctx = new AccountContext()) { var data = (from a in ctx.Accounts where a.AccountId == id select new { AccountId = a.AccountId, CustomerId = a.CustomerId, Balance = a.Balance, AccountType = (AccountType)a.AccountTypeId }).First(); return _accountFactory.Create(data.AccountId, data.CustomerId, data.Balance, data.AccountType); } } } 

更新

我对LINQ to SQL的建议是:

  1. 如果可以的话,请转到entity framework,因为它更高级,现在得到更好的支持。
  2. 不要将其生成的对象用作域对象。 如果查看上面的代码,我会查询来自ctx.Accounts的数据并使用它来实例化我的域对象。 根据我的经验,尝试使用和ORM来构建域对象是有问题的:请参阅包含行为和ORM的丰富域模型