This is a migrated thread and some comments may be shown as answers.

Does cast or IReadOnlyList break Data Access related objects context?

1 Answer 45 Views
Data Access Free Edition
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Mikhail
Top achievements
Rank 1
Mikhail asked on 26 Aug 2015, 11:38 AM

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

1 Answer, 1 is accepted

Sort by
0
Simeon Simeonov
Telerik team
answered on 31 Aug 2015, 10:10 AM
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.
Tags
Data Access Free Edition
Asked by
Mikhail
Top achievements
Rank 1
Answers by
Simeon Simeonov
Telerik team
Share this question
or