Code First Entity Framework - entity-framework

We are using Miscrosoft's code first entity framework (4.1) to map to an existing database. We want to be able to change the datatypes and values of some properties that map one to one with a table. For instance, there is a column on the table that determines if a record is current. It is an integer column, and has values 1 or 2. We don't want to change the database as there are many different applications fetching data from that colum, but it would be nice for our code to have the class that maps to that table have a bool property that is IsActive, which returns true if the table column is 1 and false otherwise. Is there a way to configure the EnityFrame work so that we can define this mapping directly without having two properties on the actual class, one for the integer column (mapped to the database) and one boolean property computed from the other? Can I map the boolean property directly to the integer column?

Simple answer is no. EF is totally stupid in this area and it is completely missing simple type mapping.
That means that you cannot change type of scalar properties and your class indeed has to work with that int property using values 1 and 2 to define your IsActive.
The workaround can be:
public class YourClass
{
public int IsActiveValue { get; set; }
[NotMapped]
public bool IsActive
{
get { return IsActiveValue == 2; }
set { IsActiveValue = value ? 2 : 1; }
}
}
This workaround has some disadvantages
You must have two properties and IsActvieValue must be visible to context
You cannot use IsActive in linq-to-entities queries

Related

Update integers (or numbers) by difference in EF Core

Does EntityFramework Core provide a way to create an update query in such way, it will create an UPDATE that calculates the change of an numeric column instead of an absolute value?
Context about the question
Consider the following DbContext:
public class MyValue {
public int Id {get;set;}
public int Value {get;set;}
}
public class MyContext : DbContext {
public DbSet<MyValue> Values {get;set;}
}
A simple command could do the following:
var newValue = new MyValue { Value = 1 };
_dbContext.Add(newValue);
_dbContext.SaveChanges();
var value = _dbContext.Values.First();
value = value + 5;
_dbContext.SaveChanges();
The resulting statement that'll be send to the database during SaveChanges()
Will be something like this:
UPDATE SET [Value] = 6 WHERE ID = 1
But I'd like it to formulate an update statement like this:
UPDATE SET [Value] = [Value] + 5 WHERE ID = 1
WHY?
If an update would be created like the second one, it'd not be neccesary for me to take precautions about concurrency. The database should be able to handle that for me.
I am aware, that I could create an StoredProcedure handling the update that way, but that seems not neccesary, if EFCore would just split the Update commands, making (all) numeric columns update by difference.
So - is there an integrated way to do that, or is there a feasible way to implement it during SaveChanges()?

Entity Framework Core (bug?) - Issue when overriding Equals in the entity

I'm using Entity Framework Core 2.1 and I'm facing a weird situation. I have a bunch of rows with the same values for some columns but different ids in the DB. When I retrieve them using EF Core, only the ones that have different values are binded to object (for ex, I have 17 rows in the DB that fulfil the conditions and I'm only getting 7 objects). My entity is overriding the Equals method so I added a breakpoint on that method and verified that EF was calling it.
EF is only retrieving "unique" rows based on the Equals method and that's a problem in my case as I keep an IsActive column that is not part of the Equals method. At the same time, my entity is overriding GetHashCode method but EF is not using it. In my opinion this is a bug.
Is there a way to workaround this problem without adding IsActive to Equals method?
Let me show a simulated version of the code:
public class EntityX
{
public int Id {get;set;}
public string Name {get;set;}
public bool IsActive {get;set;}
public override bool Equals(object obj)
{
// return true when the Name properties are the same. it's not considering IsActive property
...
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
If you have 2 rows in the DB with different IDs and different IsActive value but same name, it will only return one row because EF will call the Equals method and say "hey, these 2 rows are the same so let's keep one". In my opinion it's a bug because it should also call GetHashCode. As a rule of thumb, every time you override Equals you have to override GetHashCode and this is one of the use cases for that.
This issue was happening to me when I was doing an include, maybe EF only calls Equals when there's an include. The navigation property is a List with generics.

How to explicitly set the ID property on an autoincrementing table in EFCore

I have a model which has an auto-incrementing ID field by default as is normal. However, I wish to seed the database with initial data and because there are foreign keys I wish to explicitly set the IDs of the seeded data.
My model
public class EntAttribute
{
public int ID { get; set; }
public string Title { get; set; }
}
My seeding code:
public class Seeder
{
private class AllAttributes
{
public List<EntAttribute> Attributes { get; set; }
}
public bool SeedData()
{
AllAttributes seedAttributes;
string strSource;
JsonSerializer JsonSer = new JsonSerializer();
strSource = System.IO.File.ReadAllText(#"Data/SeedData/Attributes.json");
seedAttributes = JsonConvert.DeserializeObject<AllAttributes>(strSource);
_context.AddRange(seedAttributes.Attributes);
_context.SaveChanges();
return true;
}
}
Please note, I'm very new to both EFCore and C#. The above is what I've managed to cobble together and it seems to work right up until I save the changes. At this point I get:
SqlException: Cannot insert explicit value for identity column in table 'Attribute' when IDENTITY_INSERT is set to OFF.
Now I'm smart enough to know that this is because I can't explicitly set the ID field in the EntAttribute table because it wants to assign its own via auto-increment. But I'm not smart enough to know what to do about it.
Any help appreciated.
EDIT: Adding the solution based on the accepted answer below because the actual code might help others...
So I added to my Context class the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("EntAttributeNumbering")
.StartsAt(10);
modelBuilder.Entity<EntAttribute>()
.Property(i => i.ID)
.HasDefaultValueSql("NEXT VALUE FOR EntAttributeNumbering");
}
This first ensures the a sequence is created (the name is arbitrary) and then secondly, sets it to be used for the relevant table instead of auto-increment. Once this was done I was able to my seed data. There are fewer than 10 records so I only needed to set the start value for the sequence to 10. More would normally make sense but I know there will never be more.
I also had to blitz my migrations because they'd somehow got in a mess but that's probably unrelated.
With EF Core you can create and use a Sequence object to assign the IDs, and you can reserve a range of IDs for manual assignment by picking where the sequence starts. With a Sequence you can assign the IDs yourself, or let the database do it for you.
FYI for people using EF Core 3, if using int for your key you can set the start sequence value incase you have seeded data. I found this a much cleaner to solve this problem in my use case which just had a single seeded record.
e.g
modelBuilder.Entity<TableA>()
.Property(p => p.TableAId)
.HasIdentityOptions(startValue: 2);
modelBuilder.Entity<TableA>()
.HasData(
new TableA
{
TableAId = 1,
Data = "something"
});
https://github.com/npgsql/efcore.pg/issues/367#issuecomment-602111259

How to solve field wrapping in Entity Framework database-first

When I use database first, after creating the edmx file, all the conceptual models have already been generated. But I want to do some special operations on certain fields. For example, there's a field named 'price'; I want the matching property 'Price' to return double of the 'price'. How can I do that? If I modify the getter in the code, every time I update the model from database, all of the modifications go away.
What's the correct way to do this?
What you can do is create a partial class for entity which contains the Price Property and put a getter like this (A property with double price will be meaningful ),
Public partial class YourEntity{
Public float DoublePrice{
get { return Price*2;}
}
}
Or you can create a class inherited from the entity,
Public partial class Entity:YourEntity{
Public override float Price{
get { return base.Price*2;}
}
}

Entity Framework Code First and Collections of Primitive Types

When creating POCO classes that contain collections of primitive types and are persisted by EF Code First, the best advice I have found so far is to create a new class that has an ID plus the primitive type:
Entity Framework and Models with Simple Arrays
If I now have several classes that require properties of type ObservableCollection<string> and replace them with ObservableCollection<EntityString> (where EntityString is a custom type with an Id and a string property), I end up with a table EntityString that has multiple foreign key columns, one for each property of type ObservableCollection<EntityString> across all concrete types with such properties.
This leads to a bloating of mostly-null foreign key columns in the EntityString table.
One approach would be to create a subclass of EntityString and use the Table per Type model for those subclasses. However, that requires making awkward changes to the object model simply to accommodate Entity Framework.
Questions:
Is the encapsulating type the best way to manage Collection<PrimitiveType>?
If so, what are the pro's and con's of allowing multiple (many) foreign key columns vs. creating custom tables per type (at the cost of an awkward model)?
Promoting simple type to entity is one option. If you want to use that new primitive type entity in more relations it is better to completely remove navigation properties from that entity and use independent association (no FK properties).
public class StringEntity
{
public int Id { get; set; }
public string Text { get; set; }
}
and mapping:
modelBuilder.Entity<Foo1>().HasMany(f => f.Strings).WithOptional();
modelBuilder.Entity<Foo2>().HasMany(f => f.Strings).WithOptional();
In database you will get new nullable FK per related principal - there is no way to avoid it except create special StringEntity class per principal (don't use inheritance for that because it affects performance).
There is an alternative:
public class StringEntity
{
public int Id { get; set; }
public List<string> Strings { get; private set; }
public string Text
{
get
{
return String.Join(";", Strings);
}
set
{
Strings = value.Split(";").ToList();
}
}
}
In this case you don't need related entity type (and additional table) but your entity is polluted with additional property Text which is only for persistence.