Persist entire class as JSON using Entity Framework - entity-framework

I have found many examples of how to persist an individual member of an entity as JSON, but what about if I want the entire class persisted as JSON? For example, if I have a class:
public class MyObj
{
public int Id {get; set;}
public int[] Array {get; set;}
}
and I want it persisted in the database as:
Table: MyObjTable
Row 1:
Id: 1
MyObj: {"id": 1, "array": [1, 2, 3]}
Row 2:
Id: 2
MyObj: {"id": 2, "array": [4, 5, 6]}
What would the DbContext class look like?

It's not really about the DbContext class. You'd need to provide a property getter and setter for "MyObj" and prevent mapping of Array:
public class MyObj
{
public int Id { get; set; }
[NotMapped]
public int[] Array { get; set; }
public string Obj
{
get
{
return JsonSerializer.Serialize(this);
}
set
{
MyObj clone = JsonSerialiser.Deserialize<MyObj>(value);
Array = clone.Array;
}
}
}

If you can wait until November 2021, then you are able to use a native feature available in EF Core 6 (.NET 6.0). By then properties can be decorated with a JsonColumn (name can be different until release). Complex (and also simple / primitive) values can then be serialized into json within a column in the database. You can read more in the devblogs.

Related

Entity Framework 6 load derived class of entity

In Entity Framework 6, given class A and derived class B: A, I would like to load entities A into instances of B without having to code for each property.
So given:
public class A
{
public Guid AId { get; set; }
public string Value { get; set; }
}
public class B: A
{
[NotMapped]
public string OtherValue { get; set; }
}
public MyDbContext: DbContext
{
public DbSet<A> As { get; set; }
}
I would like to:
using (MyDbContext db = new MyDbContext())
{
IEnumerable<B> Bs = db.As.LoadBsSomehow()
}
I'm guessing I could add DbSet<B> Bs { get; set; } and then in OnModelCreate I could override the table name to As perhaps. I'd like to avoid that if I can.
The purpose of doing this is that we need view models that need the underlying model plus some other properties and I don't want to mess up the models with all the different view model properties. This would simplify coding and maintenance for when the main model is changed -- the inheritance would automatically handle the changes in the derived class (view models).
I can then set the additional properties of the Bs in a Select or other method.
Also, I do NOT want to use reflection. I can code that up if I need it. I'd rather find out if EF 6 has the ability to do this natively.
UPDATE: I can do DbContext.Database.SqlQuery<T>. I would prefer to be able to use LINQ instead of writing SQL. I have no problem writing SQL, but LINQ is much more maintainable from a code perspective. Perhaps if I can use LINQ to create an IQueryable<B> and get the SQL for it?

Create a table corresponding to enum Entity framework

I followed the below answer to insert enums into database;
How to create a table corresponding to enum in EF6 Code First?
But I am facing one strange issue. Every time I run the application, it additionally enters the last enum. For example, suppose i have three option for enum;
Started, In Progress, Done.
now on first run, it enters the 3 values as expected.
but on second run, there are four rows in database and Done is duplicated. Done is duplicated on each run.
PS:
I have done some changes from above article.
I used DatabaseGenerated(DatabaseGeneratedOption.Identity) instead of DatabaseGenerated(DatabaseGeneratedOption.None)
My table is already in database
I am using code-first approach and just wanted to re-factor code.
Am I doing anything wrong or is there any other solution to solve this?
Enum Class:
namespace ToDO.Data.Models
{
public class TaskStatus
{
private TaskStatusTaskStatusEnum #enum)
{
Id = (int)#enum;
Name = #enum.ToString();
Description = #enum.GetEnumDescription();
}
protected TaskStatus() { } //For EF
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Description { get; set; }
public static implicit operator TaskStatusTaskStatusEnum #enum) => new TaskStatus(#enum);
public static implicit operator TaskStatusEnumTaskStatus status) => (TaskStatusEnum)status.Id;
}
public enum TaskStatusEnum
{
[Description("Started")]
Started,
[Description("In Progress")]
InProgress,
[Description("Done")]
Done
}
}
EF Extenstion method to add values in database:
public static void SeedEnumValues<T, TEnum>(this IDbSet<T> dbSet, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => dbSet.AddOrUpdate(instance));
Result:
Database result
Thanks.
The AddOrUpdate does its compare with the primarykey. Enums starts from 0. This one is not in the database so it is added again. You can use AddOrUpdate(x=>x.Code.. etc

Web API OData $expand doesn't return complex types

Domain model:
public class Course
{
public int CourseId { get; set; }
public virtual ICollection<TeeSet> TeeSets { get; set; }
}
public class TeeSet
{
public int TeeSetId { get; set; }
public int CourseId { get; set; }
public CourseRating MensRating { get; set; }
}
The following query does not include the CourseRating complex type when Courses are expanded to include TeeSets.
GET /api/courses?$expand=TeeSets
public class CoursesController : ApiController
{
[Queryable]
public IQueryable<Course> Get()
{
return _uow.Courses.GetAll();
}
}
The JSON serialized result does not include the MensRating complex type (CourseRating):
[
{
"teeSets": [
{
"teeSetId": 1,
"courseId": 7
},
{
"teeSetId": 2,
"courseId": 7
}
],
"courseId": 7,
}
]
However, a quick test against the DbContext returns the CourseRating complex type on TeeSets like I would expect:
[TestMethod]
public void Get_Course_With_TeeSets()
{
using (CoursesContext ctx = new CoursesContext())
{
var courses = ctx.Courses.Where(x => x.CourseId == 7).Include(x => x.TeeSets).FirstOrDefault();
}
}
Entity Framework 6 and Web API 2 used.
You should expand MensRating as well like this, GET /api/courses?$expand=TeeSets/MensRating
When we build an implicit EDM model for supporting QueryableAttribute with ApiController, we treat every type as an entity type to get around the OData V3 limitation that complex types cannot refer to entity types. And, this means that you have to expand explicitly every non primitive type.
Add AutoExpand on MensRating Property can make this work.

Handling entity framework relations in json.net

I have an ASP MVC Web Api project that outputs json using json.net. I have for example the following models:
public class ModelA
{
public int Id {get;set;}
public string Name {get;set;}
[JsonIgnore]
public int TypeModelId {get;set;}
public virtual TypeModel TypeModel {get;set;}
}
public class TypeModel
{
[JsonIgnore]
public int Id {get;set;}
public string Name {get;set;}
[JsonIgnore]
public virtual IList<ModelA> ModelAs {get;set;}
}
When I serialize a ModelA the output will be something like this:
[
{
"Id": 1,
"Name": "test",
"TypeModel": {
"Name": "testtype1"
}
}
]
Is it possible using json.net to have an output like this..
[
{
"Id": 1,
"Name": "test",
"TypeModel": "testtype1"
}
]
..or do I have to copy the contents of ModelA to a new class which stores the TypeModel relation as string instead of reference? Maybe there are better solutions?
As you say the only way to do this is with a DTO. This is because, as you indicated, the type of TypeModel is a class TypeModel and not a string. If you are using Linq you could also just use an anonymous type in the following way.
return db.ModelAs.Single(x=>x.Id == id).Select(x=> new{
x.Id,
x.Name,
TypeModel = x.TypeModel.Name
});
Actually this is not true, json.net can handle loop reference handling, dto is an old method, still good, but you can enable in the serializer the option to handle loopreferences as long as it is mvc5 and maybe also mvc4.
More details here: https://stackoverflow.com/a/23044770/1345207

Using enums with Entity Framework 4.1 code first

I am using entity framework 4.1 code first.
I have a GrantApplication class:
public class GrantApplication
{
// Just some of the properties are listed
public int Id { get; set; }
public GrantApplicationState GrantApplicationState { get; set; }
}
GrantApplicationState is an enum and looks like this:
public enum GrantApplicationState
{
Applying = 1,
Submitted = 2,
cknowledged = 3
}
Just before I go and add the grant application the database I set the grant application state:
public void Insert(GrantApplication grantApplication)
{
// Set the current state to applying
grantApplication.GrantApplicationState = GrantApplicationState.Applying;
// Insert the new grant application
grantApplicationRepository.Insert(grantApplication);
}
In my database I have a GrantApplication table with a GrantApplicationStateId that links to a GrantApplicationState table.
How do I get EF to add the state id from GrantApplication.GrantApplicationState to the GrantApplicationStateId column? Is this possible? And when I retrieve the GrantApplication object then it will need to be set as well. Is this the way to do it or do I have to create another property in my GrantApplication class called GrantApplicationStateId?
You must create another property:
public class GrantApplication
{
public int Id { get; set; }
...
public int GrantApplicationStateId { get; set; }
[NotMapped] // Perhaps not need
public GrantApplicationState GrantApplicationState
{
get { return (GrantApplicationState)GrantApplicationStateId; }
set { GrantApplicationStateId = (int)value; }
}
}
EFv4.1 doesn't support enums at all - you cannot map them. This will change in EFv4.2.
Still EF not support for Enums.. it will be on EF 5.0..check my try on here
http://the--semicolon.blogspot.com/p/handling-enum-in-code-first-entity.html