SQL Server Does Entity Framework support differing data types in the model?

sxissh06  于 2023-06-28  发布在  其他
关注(0)|答案(3)|浏览(115)

I am considering to use EF to access legacy SQL Server databases installed on our customers' systems.

The problem is that the databases schemas are not 100% consistent: While they all have the same (relevant) tables and fields, some numeric fields might have different data types.

As far as I can see, the types are "compatible" from an application point of view: E.g. a field containing small numbers might be a smallint on customer A's database, but an int on customer B's database, or a field containing a price might be a decimal(10,2) on A's database but a float on B's database (yes, that means that B might suffer from floating-point problems -- it's a legacy database after all).

Since we are not the only ones accessing the databases, changing (and, thus, unifying) the schemas is not an option. Is Entity Framework able to cope with that (i.e., will it gracefully accept a double in the SQL Server table if the model definition claimed it's a decimal(10,2) ) or will it crash horribly?

htrmnn0y

htrmnn0y1#

If you look on StackOverflow you will find many questions that ask how to map one datatype in the database to another:

Short to Bool

'Y'/'N' to true/false.

Convert from to string in database to boolean property Entity Framework 4.1

time(0) to DateTime

Nearly always the solution is to have 2 fields in the entity, with code to do the explicit conversion.

A small number of DataTypes can be mapped using the FluentAPI and you could use custom code first conventions:

datetime2 to DateTime

Your smallint to int will fall into this category but I am pretty sure float to decimal(10, 2) will not.

Your problem is compounded by having multiple databases with different datatypes so I don't think EF by itself is going to work very well.

I can think of two things you could try:

Create Views in each of the databases that map datatypes consistently, then reverse engineer the Entity Framework from the Views. You will also probably have to map the CUD to stored procedures then modify the Create and Update sql for each database to convert the dataypes.

OR

Look at Dapper where you have greater control over the sql and do conversions there. There are links to hybrid implementations of the repository pattern at this answer EF + Dapper Hybrid Implementation

oxcyiej7

oxcyiej72#

Is Entity Framework able to cope with that (i.e., will it gracefully accept a double in the SQL Server table if the model definition claimed it's a decimal(10,2)) or will it crash horribly

I think that will not cause an issue as entity framework make all the conversions needed before executing the query and as there is no implicit conversion from floating-point to decimal you should detect it at compile time and make the explicit conversion.

tpgth1q7

tpgth1q73#

This is a very late answer to the question, but we have just had exactly the same issue as the OP - a client with some fields defined as int, whilst another client had those fields defined as bigint. Apologies if this solution exists somewhere else - I looked but didn't find it.

This may not be the prettiest solution but it works well where the problem isn't widespread (which would justify separate database contexts). In our case it's a single table that has manifested the problem, and changing the types in the database is a less preferred option (risk, deployment constraints, client dependencies).

First create client specific entities for the same table:

[Table("DbTableName")]
public class EntityForClientA
{
    public long Id { get; set; }
    public long GroupId { get; set; }
    //Alongside fields that don't differ
}

[Table("DbTableName")]
public class EntityForClientB
{
    public int Id { get; set; }
    public int GroupId { get; set; }
    //Alongside fields that don't differ
}

Then in the datasource:

public DbSet<EntityForClientA> EntitiesA { get; set; }
    public DbSet<EntityForClientB> EntitiesB { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        if (isClientA) modelBuilder.Ignore<EntityForClientB>();
        else modelBuilder.Ignore<EntityForClientA>();
        base.OnModelCreating(modelBuilder);
    }

From there we create business models which access the correct entity according to the client being served.

相关问题