多态性:是的ORM实体域实体或实体的数据?实体、多态性、是的、数据

2023-09-02 21:53:31 作者:厮磨

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

  [全球:: System.Data.Linq.Mapping.TableAttribute(NAME =dbo.BankAccount)
公共部分类的BankAccount:INotifyPropertyChanging,INotifyPropertyChanged的
 

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

对于不同的问题与这个例子中,我有以下两点意见。

@mouters:它的怪异,你有资源库的对象和领域对象 - 要你的资料库不只是返回的域对象 @SonOfPirate:工厂应该用于创建基于从数据存储检索的数据实例的存储库

问题

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

2)如何工厂应该由存放库可以用于创建基于从数据存储器中检索到的数据的实例?任何code例子或参考?

3)它会满足单一职责原则?

code

 公共接口IBankAccount
{
    INT BankAccountID {获得;组; }
    双平衡{获得;组; }
    字符串AccountStatus {获得;组; }
    无效FreezeAccount();
    无效AddInterest();
}

公共类FixedBankAccount:IBankAccount
{

    公众诠释BankAccountID {获得;组; }
    公共字符串AccountStatus {获得;组; }
    公共双平衡{获得;组; }

    公共无效FreezeAccount()
    {
        AccountStatus =冻结;
    }

}


公共类BankAccountService
{
    RepositoryLayer.IRepository< RepositoryLayer.BankAccount> accountRepository;
    ApplicationServiceForBank.IBankAccountFactory bankFactory;

    公共BankAccountService(RepositoryLayer.IRepository< RepositoryLayer.BankAccount>回购,IBankAccountFactory bankFact)
    {
        accountRepository =回购;
        bankFactory = bankFact;
    }

    公共无效FreezeAllAccountsForUser(INT用户id)
    {
        IEnumerable的< RepositoryLayer.BankAccount> accountsForUser = accountRepository.FindAll(P => p.BankUser.UserID ==用户id);
        的foreach(RepositoryLayer.BankAccount oneOfRepositoryAccounts在accountsForUser)
        {
            DomainObjectsForBank.IBankAccount domainBankAccountObj = bankFactory.CreateAccount(oneOfRepositoryAccounts);
            如果(domainBankAccountObj!= NULL)
            {
                domainBankAccountObj.BankAccountID = oneOfRepositoryAccounts.BankAccountID;
                domainBankAccountObj.FreezeAccount();

                this.accountRepository.UpdateChangesByAttach(oneOfRepositoryAccounts);
                oneOfRepositoryAccounts.Status = domainBankAccountObj.AccountStatus;
                this.accountRepository.SubmitChanges();
            }

        }
    }



}


公共接口IBankAccountFactory
{
    DomainObjectsForBank.IBankAccount CreateAccount(RepositoryLayer.BankAccount repositoryAccount);
}


公共类MySimpleBankAccountFactory:IBankAccountFactory
{
    //是否正确的接受repositry厂内?
    公共DomainObjectsForBank.IBankAccount CreateAccount(RepositoryLayer.BankAccount repositoryAccount)
    {
        DomainObjectsForBank.IBankAccount ACC = NULL;

        如果(String.Equals(repositoryAccount.AccountType,固定))
        {
            ACC =新DomainObjectsForBank.FixedBankAccount();
        }

        如果(String.Equals(repositoryAccount.AccountType,储蓄))
        {
            // ACC =新DomainObjectsForBank.SavingsBankAccount();
        }

        返回ACC;
    }
}
 

阅读

CAD图层实体数据转换为SHP

设置外键的LINQ to SQL

在LINQ多态关联到SQL

Confusion的DTO(LINQ2SQL)和类对象之间!

LINQ到XYZ多态性?

解决方案 我不是很确定你所要求的关于LINQ to SQL的,但它肯定不是错误的方法来手动创建你的域对象。你不会得到正确的封装领域对象,如果你依靠他们是code产生的。

您已经得到了自己在有关工厂模式的混乱。正如mouters指出,你有两个对象再presenting同样的事情:

RepositoryLayer.BankAccount

DomainObjectsForBank.IBankAccount

当一个战略要求创建对象时,才需要

工厂。一个经典的案例供其使用的多态及放大器;遗产。您的帐户类有子类,所以有一个AccountFactory的情况。但是,在你有过复杂的情况是由具有存储库返回某种帐户数据的对象,然后通过这个工厂将其转换为正确的子归类域对象。相反,存储库应该从数据库中的数据,将其传递给工厂,然后从工厂返回创建域对象。例如:

 公共类AccountRepository:IAccountRepository
{
    公共账号GetById(GUID ID)
    {
        使用(AccountContext CTX =新AccountContext())
        {
            VAR数据=(从在ctx.Accounts
                               其中,a.AccountId == ID
                               选择新{的AccountId = a.AccountId,客户ID = a.CustomerId,余额= a.Balance,AccountType =(AccountType)a.AccountTypeId})(第)。


            返回_accountFactory.Create(data.AccountId,data.CustomerId,data.Balance,data.AccountType);
        }
    }

}
 

更新

我就LINQ to SQL的建议是:

将实体框架,如果你可以因为它更先进,现在更好的支持。 请不要使用它生成的对象作为你的域对象。如果你看一下code以上,我从我的ctx.Accounts查询数据,并用它来实例化我的域对象。以我的经验试图用和ORM建立域对象是有问题的:见Rich用行为和ORM域模型

I have a BankAccount table. LINQ to SQL generates a class named "BankAccount" as shown below.

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

Now, being a newbie, I am newly creating the domain objects myself. Please see IBankAccount interface and FixedBankAccount class. The key point is there is polymorphic behavior – the IBankAccount can be FixedBankAccount or SavingsBankAccount.

For a different question with this example, I have following two comments.

@mouters : "Its weird that you have repository objects and domain objects - should your repository not just return the domain objects?" @SonOfPirate : "The factory should be used by the repository to create the instance based on the data retrieved from the data store."

QUESTIONS

1) I am manually creating domain entities. Is it wrong approach? If it is wrong, how the LINQ to SQL classes handle the polymorphism? How to add the methods to those classes?

2) How the factory should be used by the repository to create the instance based on the data retrieved from the data store? Any code example or reference ?

3) Will it satisfy Single Responsibility Principle?

CODE

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;
    }
}

READING:

Setting Foreign keys in Linq to SQL

Polymorphic associations in LINQ to SQL

Confusion between DTOs (linq2sql) and Class objects!

LINQ-to-XYZ polymorphism?

解决方案

I'm not entirely sure what you are asking regarding LINQ to SQL, but it's certainly not the wrong approach to manually create you domain objects. You won't get properly encapsulated domain objects if you rely on them being code generated.

You have got yourself in a muddle regarding the factory pattern. As mouters has pointed out, you have two objects representing the same thing:

RepositoryLayer.BankAccount

DomainObjectsForBank.IBankAccount

Factories are only required when a 'strategy' is required for object creation. A classic case for their use is polymorphism & inheritance. Your account class has sub classes, so there is a case for an AccountFactory. But where you have over complicated the situation is by having the repository return some kind of account data object, then passing this to the factory to convert it to the correct sub classed domain object. Instead, the repository should get the data from the database, pass it to the factory, and then return the created domain object from the factory. For example:

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);
        }
    }

}

UPDATE:

My Advice regarding LINQ to SQL is:

Move to Entity Framework if you can as it's more advanced and is better supported now. Don't use it's generated objects as your domain objects. If you look at the code above, I query the data from my ctx.Accounts and use it to instantiate my domain objects. In my experience trying to use and ORM to build domain objects is problematic: see Rich domain model with behaviours and ORM

 
精彩推荐
图片推荐