Does cast or IReadOnlyList break Data Access related objects context?

2 posts, 0 answers
  1. Mikhail
    Mikhail avatar
    2 posts
    Member since:
    Aug 2014

    Posted 26 Aug 2015 Link to this post

    Hi.

    I've got Clients and VIPClients entities in a database. Both of them are generated by Data Access Visual Designer. For some reason (I support the project, so I don't know why) these generated classes also have partial classes with additional logic. Both of them also implemented IClient in these partial classes. 

    In some moment program collect all clients by union into IReadOnlyList<IClient> and save them. Save method is below:

    public void Save(IReadOnlyList<IClient> clients) {
         foreach(var client in clients) {
            if(client is Client) {
                var cclient = client as Client;
                cclient.CompanyId = _companyId;
                _database.Add(cclient);
                _database.SaveChanges();​
            }
     
            if(client is VIPClient) {
                var cclient = client as VIPClient;
                cclient.CompanyId = _companyId;
                _database.Add(cclient);
                _database.SaveChanges();​
            }​
        }
    }

    Clients and VIPClients have Company (one Company has a lot of Clients). In the code above _companyId is Id of existed Company that already in database. But for some reason Data Access tries to insert Company in database instead of just inserting Client or VIPClient. Why can this occur? 

     I found the solution, but it's ugly:

    public void Save(IReadOnlyList<IClient> clients) {
         foreach(var client in clients) {
            if(client is Client) {
                var cclient = client as Client;
                cclient.CompanyId = _companyId;
                 
                var company = _database.Companies.SingleOrDefault(c=>c.Id == _companyId);
                if(company != null) {
                    cclient.Company = company;
                }
                 
                _database.Add(cclient);
                _database.SaveChanges();​
            }
     
            if(client is VIPClient) {
                var cclient = client as VIPClient;
                cclient.CompanyId = _companyId;
                 
                var company = _database.Companies.SingleOrDefault(c=>c.Id == _companyId);
                if(company != null) {
                    cclient.Company = company;
                }
                 
                _database.Add(cclient);
                _database.SaveChanges();​
            }​
        }
    }

  2. Simeon Simeonov
    Admin
    Simeon Simeonov avatar
    24 posts

    Posted 31 Aug 2015 Link to this post

    Hi Mikhail,

    Thank you for contacting us.

    I have tried to reproduce your issue but I was not able to. I have created in the designer the following mapping: link. I have created a Company and stored it in the database and after that I have executed the following code:
    using (var context = new EntitiesModel())
    { 
        Client newClient = new Client { Name = "Client1", CompanyId = _companyId };
        context.Add(newClient);
     
        VipClient newVipClient = new VipClient { Name = "VipClient1", CompanyId = _companyId };
        context.Add(newVipClient);
     
        context.SaveChanges();
    }

    The clients were created and correctly linked to the existing company.

    In order to examine the created mapping on my end I have changed the code generated mapping type to Fluent mapping like this: open the RLINK Model settings\ Code generation tab, in it I have changed the Mapping type in the combobox from the default (XML) to Fluent. The generated fluent mapping in my FluentMetadataSource file for the Company, Client and VipClient looks like this:
    public void PrepareCompanyPropertyConfigurations(MappingConfiguration<Company> configuration)
    {
        configuration.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc).HasFieldName("_id").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Id").IsNotNullable().HasColumnType("int").HasPrecision(0).HasScale(0);
        configuration.HasProperty(x => x.Name).HasFieldName("_name").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Name").IsNotNullable().HasColumnType("nvarchar").HasLength(255);
    }
     
    public void PrepareCompanyAssociationConfigurations(MappingConfiguration<Company> configuration)
    {
        configuration.HasAssociation(x => x.VipClients).HasFieldName("_vipClients").WithOpposite(x => x.Company).ToColumn("CompanyId").WithDataAccessKind(DataAccessKind.ReadWrite);
        configuration.HasAssociation(x => x.Clients).HasFieldName("_clients").WithOpposite(x => x.Company).ToColumn("CompanyId").WithDataAccessKind(DataAccessKind.ReadWrite);
    }

    ...
     
    public void PrepareClientPropertyConfigurations(MappingConfiguration<Client> configuration)
    {
        configuration.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc).HasFieldName("_id").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Id").IsNotNullable().HasColumnType("int").HasPrecision(0).HasScale(0);
        configuration.HasProperty(x => x.Name).HasFieldName("_name").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Name").IsNotNullable().HasColumnType("nvarchar").HasLength(255);
        configuration.HasProperty(x => x.CompanyId).HasFieldName("_companyId").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("CompanyId").IsNotNullable().HasColumnType("int").HasPrecision(0).HasScale(0);
    }
     
    public void PrepareClientAssociationConfigurations(MappingConfiguration<Client> configuration)
    {
        configuration.HasAssociation(x => x.Company).HasFieldName("_company").WithOpposite(x => x.Clients).ToColumn("CompanyId").IsRequired().WithDataAccessKind(DataAccessKind.ReadWrite);
    }

    ...
     
    public void PrepareVipClientPropertyConfigurations(MappingConfiguration<VipClient> configuration)
    {
        configuration.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc).HasFieldName("_id").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Id").IsNotNullable().HasColumnType("int").HasPrecision(0).HasScale(0);
        configuration.HasProperty(x => x.Name).HasFieldName("_name").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("Name").IsNotNullable().HasColumnType("nvarchar").HasLength(255);
        configuration.HasProperty(x => x.CompanyId).HasFieldName("_companyId").WithDataAccessKind(DataAccessKind.ReadWrite).ToColumn("CompanyId").IsNotNullable().HasColumnType("int").HasPrecision(0).HasScale(0);
    }
     
    public void PrepareVipClientAssociationConfigurations(MappingConfiguration<VipClient> configuration)
    {
        configuration.HasAssociation(x => x.Company).HasFieldName("_company").WithOpposite(x => x.VipClients).ToColumn("CompanyId").IsRequired().WithDataAccessKind(DataAccessKind.ReadWrite);
    }


    Could you check the Fluent mapping generated for your Company, Client and VipClient entities and compare it with mine.

    Also the issue you are facing sounds like something related to the management of your navigation properties. Could you try making your navigation properties managed. For more details what will be the result of such a change and how to do it please take a look at this link and this link

    Regards,
    Simeon Simeonov
    Telerik
     
    Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
  3. DevCraft banner
Back to Top