Polimorfismo: ¿la entidad ORM es una entidad de dominio o entidad de datos?

Tengo una tabla de cuentas bancarias. LINQ to SQL genera una clase llamada “BankAccount” como se muestra a continuación.

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

Ahora, como novato, estoy creando los objetos de dominio por mi cuenta. Consulte la interfaz IBankAccount y la clase FixedBankAccount. El punto clave es que existe un comportamiento polimórfico: IBankAccount puede ser FixedBankAccount o SavingsBankAccount.

Para una pregunta diferente con este ejemplo, he seguido dos comentarios.

  1. @mouters: “Es extraño que tengas objetos de repository y objetos de dominio, ¿tu repository no solo debe devolver los objetos de dominio?”
  2. @SonOfPirate: “La fábrica debe ser utilizada por el repository para crear la instancia basada en los datos recuperados del almacén de datos”.

PREGUNTAS

1) Estoy creando entidades de dominio manualmente. ¿Es un enfoque equivocado? Si es incorrecto, ¿cómo manejan las clases LINQ a SQL el polymorphism? ¿Cómo agregar los métodos a esas clases?

2) ¿De qué manera la fábrica debe ser utilizada por el repository para crear la instancia basada en los datos recuperados del almacén de datos? Cualquier ejemplo de código o referencia?

3) ¿Satisfará el Principio de Responsabilidad Individual?

CÓDIGO

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

LECTURA :

  1. Configuración de claves externas en Linq a SQL

  2. Asociaciones polimórficas en LINQ to SQL

  3. ¡Confusión entre DTO (linq2sql) y objetos de Clase!

  4. Polimorfismo LINQ-to-XYZ?

  1. No estoy del todo seguro de lo que está preguntando sobre LINQ to SQL, pero ciertamente no es el enfoque incorrecto para crear manualmente objetos de dominio. No obtendrá objetos de dominio encapsulados adecuadamente si confía en que sean generados por código.
  2. Te has metido en un embrollo con respecto al patrón de fábrica. Como ha señalado mouters, tiene dos objetos que representan lo mismo:

    RepositoryLayer.BankAccount

    DomainObjectsForBank.IBankAccount

Las fábricas solo son necesarias cuando se requiere una ‘estrategia’ para la creación de objetos. Un caso clásico para su uso es el polymorphism y la herencia. Su clase de cuenta tiene sub clases, por lo que hay un caso para una AccountFactory. Pero donde se ha complicado la situación es haciendo que el repository devuelva algún tipo de objeto de datos de cuenta, y luego pasarlo a la fábrica para convertirlo en el objeto de dominio subclasificado correcto. En cambio, el repository debe obtener los datos de la base de datos, pasarlos a la fábrica y luego devolver el objeto de dominio creado de fábrica. Por ejemplo:

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

ACTUALIZAR :

Mi consejo con respecto a LINQ to SQL es:

  1. Vaya a Entity Framework si puede, ya que es más avanzado y está mejor admitido ahora.
  2. No use sus objetos generados como objetos de su dominio. Si miras el código anterior, consulto los datos de mi cuenta ctx.Accounts y los utilizo para instanciar mis objetos de dominio. En mi experiencia, tratar de usar y ORM para construir objetos de dominio es problemático: vea el modelo de dominio Rich con comportamientos y ORM