none
LINQ to SQL: Programming Against Interfaces RRS feed

  • Question

  • Hi,

    I'm planing to develop my framework based on LINQ to SQL so the dependency injection is one of key features. Also, the inheritance in classes implemented by using interfaces and data classes and Associations defined in entity classes. I prepare a sample about what i plan to do. But there is a problem that i need help to solve it. I'll appreciate who could to help me.

    here is sample: http://www.saeedtaheri.ws/SampleProject.zip

    If you find out the problem please modify this code and let me know about the changes.

    Important Note: The Id in data and entity class is " int? " because when you create an instance, you don't know the value of Id, better sample is in parent - child relationship (in CSDL we should able to define the key as nullable too) but in database Id is NOT NULL because of primary key role it have (in SSDL we do this)

    Thank you

    Saeed Taheri

    Saturday, April 24, 2010 3:32 PM

All replies

  • I will gladly help you, but please post the concrete question here, together with a simplified code snippet - much easier and everybody can attend :)
    Monday, April 26, 2010 9:27 AM
  • Hi,

    Thank you for you help, the concrete question is that i implement the entity model like this:

    in Common for all entities:

     public interface IModelBase
     {
      int? Id
      {
       get;
       set;
      }
     }

     public class ModelBase : IModelBase
     {

      public virtual int? Id
      {
       get;
       set;
      }
     }

    and Customer model:

     public interface ICustomerData : IModelBase
     {
      string FullName
      {
       get;
       set;
      }

      string CountryName
      {
       get;
       set;
      }
     }

     public class CustomerData : ModelBase, ICustomerData
     {
      public virtual string FullName
      {
       get;
       set;
      }

      public virtual string CountryName
      {
       get;
       set;
      }
     }

     public interface ICustomerEntity : ICustomerData
     {
      EntitySet<IOrderEntity> theOrders
      {
       get;
       set;
      }
     }

     [Table(Name = "TBL_Customer")]
     public class CustomerEntity : CustomerData, ICustomerEntity
     {
      private EntitySet<IOrderEntity> _theOrders;

      private void attach_Order(IOrderEntity order)
      {
       order.theCustomer = this;
      }

      private void detach_Order(IOrderEntity order)
      {
       order.theCustomer = null;
      }

      public CustomerEntity()
      {
       _theOrders = new EntitySet<IOrderEntity>(new Action<IOrderEntity>(attach_Order), new Action<IOrderEntity>(detach_Order));
      }

      [Column(Name = "Id")]
      public override int? Id
      {
       get
       {
        return base.Id;
       }
       set
       {
        base.Id = value;
       }
      }

      [Column(Name = "FullName")]
      public override string FullName
      {
       get
       {
        return base.FullName;
       }
       set
       {
        base.FullName = value;
       }
      }

      [Column(Name = "CountryName")]
      public override string CountryName
      {
       get
       {
        return base.CountryName;
       }
       set
       {
        base.CountryName = value;
       }
      }

      [Association(Name = "Customer_theOrder", Storage = "_theOrders", ThisKey = "Id", OtherKey = "CustomerId", IsForeignKey = true)]
      public EntitySet<IOrderEntity> theOrders
      {
       get
       {
        return _theOrders;
       }
       set
       {
        _theOrders.Assign(value);
       }
      }
     }

    and the Order entity:

     public interface IOrderData : IModelBase
     {
      string ProductName
      {
       get;
       set;
      }

      int? Quantity
      {
       get;
       set;
      }

      int? CustomerId
      {
       get;
       set;
      }
     }

     public class OrderData : ModelBase, IOrderData
     {
      public virtual string ProductName
      {
       get;
       set;
      }

      public virtual int? Quantity
      {
       get;
       set;
      }

      public virtual int? CustomerId
      {
       get;
       set;
      }
     }

     public interface IOrderEntity : IOrderData
     {
      ICustomerEntity theCustomer
      {
       get;
       set;
      }
     }

     [Table(Name = "TBL_Order")]
     public class OrderEntity : OrderData, IOrderEntity
     {
      [Column(Name = "Id")]
      public override int? Id
      {
       get
       {
        return base.Id;
       }
       set
       {
        base.Id = value;
       }
      }

      [Column(Name = "CustomerId")]
      public override int? CustomerId
      {
       get
       {
        return base.CustomerId;
       }
       set
       {
        base.CustomerId = value;
       }
      }

      [Column(Name = "ProductName")]
      public override string ProductName
      {
       get
       {
        return base.ProductName;
       }
       set
       {
        base.ProductName = value;
       }
      }

      [Column(Name = "Quantity")]
      public override int? Quantity
      {
       get
       {
        return base.Quantity;
       }
       set
       {
        base.Quantity = value;
       }
      }

      public ICustomerEntity theCustomer
      {
       get;
       set;
      }
     }

    in LINQ to SQL data context i implement it very simple:

     [Database(Name = "SampleDb")]
     public class SampleDbContext : DataContext
     {
      private static MappingSource _mappingSource = new AttributeMappingSource();

      public SampleDbContext(string connection)
       : base(connection, _mappingSource)
      {
      }
     }

    now, if you in Main method create an instance of SimpleDbContext and query the customer:

       ICustomerEntity customerEntity = dataContext.GetTable<CustomerEntity>().Where(customer => string.Equals(customer.FullName, "Saeed")).SingleOrDefault();
       foreach (IOrderEntity order in customerEntity.theOrders)
       {
        Console.WriteLine("Order {0} : {1}", order.Id, order.ProductName);
       }

    there are two problem, first you receive an InvalidOperationException with message:

    Could not find key member 'CustomerId' of key 'CustomerId' on type 'IOrderEntity'. The key may be wrong or the field or property on 'IOrderEntity' has changed names.

     

    if you move the Association attribute to the ICustomerEntity, the problem fixed because the DataContext could to find the association but customerEntity.theOrders is empty. If you generate entities by SqlMetal, and do it with generated entities, it returns orders. I think that the sample is the best way to review.

     

    Best Regards,

    Saeed

    Monday, April 26, 2010 9:47 AM
  • Kinda strange I must admit, at least with my skills :-|

    If you just look into customerEntity.theOrders , then which properties does this expose?

     

    Monday, April 26, 2010 12:08 PM
  • When you retreive the customerEntity, it contains the information about customer stored in the TBL_Customer in database. theOrders property as it defined is the EntitySet that contains orders made by the selected customer stored in the TBL_Order. After retreving the chosen customer, loop on orders and write the order id and ordered product name.

    In this implementation, Data classes participate in inheritance hierarchy and share fields and Entity classes for those conceptual classes that have relationship define the associations so the associations not inherited by subclasses.

    Monday, April 26, 2010 2:15 PM

  • When you retreive the customerEntity, it contains the information about customer stored in the TBL_Customer in database. theOrders property as it defined is the EntitySet that contains orders made by the selected customer stored in the TBL_Order. After retreving the chosen customer, loop on orders and write the order id and ordered product name.

    In this implementation, Data classes participate in inheritance hierarchy and share fields and Entity classes for those conceptual classes that have relationship define the associations so the associations not inherited by subclasses.


    Yes I'm aware of all that, but since we both did the same thinking regarding CustomerId, I had to ask ;) and still we don't know anything about why the CustomerId is missing. The reason for my question is that; could there exist other properties that you think should be available but aren't? Or is it just the relation key?
    Monday, April 26, 2010 4:07 PM
  • Id in ModelBase is the primary key in both customer and order conceptual data and entity classes. The relation between the customer and order is an association defined by Customer.Id and Order.CustomerId . There is only one relation between them.

    I omit the Association attribute in OrderEntity for theCustomer because in first step i only want to navigate from customer to order.

    In completely generated my domain model (database for my framework) i have these problems too, so to simplifying the concept i create this sample.

    Monday, April 26, 2010 4:25 PM
  • Hi,

    I changed all the ICustomerEntity and IOrderEntity in members to CustomerEntity and OrderEntity ( for example EntitySet<IOrderEntity> to EntitySet<OrderEntity> and so on) and it works but with interface it's not, what do you think about it?

    Tuesday, April 27, 2010 3:37 PM
  • Hi Saeed

    It's beyond my skills to say why it did the trick, but I'm very interested in knowing answer :), I think we should ask a Linq-guru, maybe someone in the ADO.NET team if possible or maybe Huagati can tell us some secrets :)

    Thank you for keeping this updated.

    Tuesday, April 27, 2010 5:31 PM
  • Hi,

    Could you contact to someone in that team?

    Tuesday, April 27, 2010 6:45 PM