0

我有一个 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:“你有存储库对象和域对象很奇怪——你的存储库不应该只返回域对象吗?”</li>
  2. @SonOfPirate:“存储库应该使用工厂来根据从数据存储中检索到的数据创建实例。”</li>

问题

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<RepositoryLayer.BankAccount> accountRepository;
    ApplicationServiceForBank.IBankAccountFactory bankFactory;

    public BankAccountService(RepositoryLayer.IRepository<RepositoryLayer.BankAccount> repo, IBankAccountFactory bankFact)
    {
        accountRepository = repo;
        bankFactory = bankFact;
    }

    public void FreezeAllAccountsForUser(int userId)
    {
        IEnumerable<RepositoryLayer.BankAccount> 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)和类对象之间的混淆!

  4. LINQ-to-XYZ 多态性?

4

1 回答 1

1
  1. 我不完全确定您对 LINQ to SQL 的要求是什么,但是手动创建域对象肯定不是错误的方法。如果您依赖它们生成代码,您将无法获得正确封装的域对象。
  2. 您对工厂模式感到困惑。正如mouters 所指出的,您有两个代表同一事物的对象:

    RepositoryLayer.BankAccount

    DomainObjectsForBank.IBankAccount

只有在对象创建需要“策略”时才需要工厂。使用它们的一个经典案例是多态性和继承。您的帐户类有子类,因此有一个 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. 如果可以,请移至实体框架,因为它更高级并且现在得到更好的支持。
  2. 不要将它生成的对象用作您的域对象。如果您查看上面的代码,我会从我的 ctx.Accounts 中查询数据并使用它来实例化我的域对象。根据我的经验,尝试使用 ORM 来构建域对象是有问题的:请参阅Rich domain model with behavior and ORM
于 2012-06-29T09:07:06.840 回答