Circular reference issue in webapi2 - c#

Scenario:
An Intern can learn multiple technologies
db design
ef view
Result
controller code:
private InternEntities db = new InternEntities();
// GET: api/Interns
public IQueryable<Intern> GetInterns()
{
return db.Interns;
}
What am i doing wrong here?

This is an expected error, and the reason is because your types reference each other like an Infinity Mirror. In order to solve the problem, you have several options.
1- You can develop a ViewModel and then serialize that one:
public class InternViewModel{
public int Id {get; set;}
public String Name {get; set;}
public List<String> Tehcnologies {get; set;}
}
2- You can select the properties that you need when returning the entity in your actions:
public async Task<List<Technology>> Get() {
var data = dbContext.Set<Technology>().Select(x=> new Technology{
Id = x.Id,
Name = x.Name,
Intern= new Intern {
Id = x.Technology.Id,
Name = x.Technology.Name,
Technologies = null
}
});
return await data.ToListAsync();
}
3- Load only the what you need which is known as Explicit Loading.

Related

How to add a List<> data to a List<> variable using EF Core C#

I am creating a CRUD Web API and I am just following this Microsoft tutorial. In my case, I have two models:
First_Model.cs:
// i removed other unnecessary data
public string Id { get; set; }
public IList<Second_Model> Second_Models {get; set;} = new List<Second_Model>();
Second_Model.cs:
// i removed other unnecessary data
public string Id { get; set; }
Just like in the tutorial, it will statically add a default value of the collection, so I want to add List<Second_Model> into Second_Models
Here's what I tried in my First_ModelController.cs
_context.First_Models.Add(
new First_Model {
Id = "default_id",
Second_Models = new List<Second_Model>() {
new List<Second_Model>().Find(p => p.Id == "default_id")
// given that Second_Model also has default_id
};
}
);
However, this set of codes will return this error:
ArgumentNullException: Value cannot be null. Parameter name: key
Statically creating a list of objects would look more like this:
....
Id = "default_id",
Second_Models = new List<Second_Model>() {
new Second_Model() { Id = "<your second model ID 1>", OtherProperty = <value> },
new Second_Model() { Id = "<your second model ID 2>", OtherProperty = <value> },
}
However, if you are want to add them directly to the context, you would do something similar to:
_context.Second_Models.Add(
new Second_Model() {
Id = "<your second model ID 1>",
OtherProperty = <value>,
}
);
... repeat ...
That does not associate the second_model with the first_model though.
You might need to read more about defining foreign keys on EF models so make this all join together, because I don't think the tutorial includes anything related to that.

Dynamically mapping nested objects with CSVHelper

I'm using CSVHelper (thanks Josh Close) to read a CSV file which works great. I'm now trying to use it to map that file to some internal classes; however, the CSV's I'm mapping vary by customer but all need to map to my internal classes. I need to allow the customer to define how the CSV maps to my POCO objects.
I'm storing the customer defined mappings as Dictionary<string,int> -- ["Firstname", 20],["Lastname",21],["Address.Line1",30], ["Address.Line2",31], etc.
I have a dynamic map class that works for dynamically mapping based on a given mapping at runtime. My problem lies in dealing with reference type properties. Here is what I have so far.
POCO Classes
public class Client
{
public int Id {get; set;}
public string Firstname {get; set;}
public string Lastname {get; set;}
public Address Address {get; set;}
...
}
public class Address
{
public string Line1 {get; set;}
public string Line2 {get; set;}
public string City {get; set;}
...
}
Based on a few posts that I've run across here and here, I came up with the following that uses a defined mapping to map a CSV dynamically.
Dynamic Map
public class BaseCSVMap<T> : ClassMap<T> where T : class
{
public void CreateMap(Dictionary<string,int> mappings)
{
foreach(var mapping in mappings)
{
var propname = mapping.Key;
var csvIndex = mapping.Value;
var member = typeof(T).GetProperty(propname);
Map(typeof(T), member).Index(csvIndex);
}
}
}
Using Dynamic Map
var id = 2; //Customer 2
var mappings = dataContext.Mappings.Where(m => m.id = id); //Get customer 2's map
using(var reader = File.OpenText(#"c:\temp\testfile.csv"))
{
var csv = new CsvReader(reader);
csv.Configuration.HasHeaderRecord = true; //hardcoded for now
var map = new BaseCSVMap<Client>();
map.CreateMap(mappings);
csv.Configuration.RegisterClassMap(map);
var records = csv.GetRecords<Client>();
}
I added the following in my BaseCSVMap<T> class, which works great if all my reference properties are strings, but doesn't work so well when a property is something else.
var member = typeof(T).GetProperty(propname);
//New code
//Mapping would look like ["Address.Line1",78]
if(member.GetType().IsClass)
{
string exp = $"c.{propname}";
var p = Expression.Parameter(typeof(T), "c");
var e = System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(new [] {p}, null, exp);
Map((Expression<Func<T,string>>)e).Index(csvIndex);
}
I also looked for a way to take advantage of the Reference mapping that CSVHelper makes available, but was unable to figure out how to do that in a dynamic fashion.
Looking for some guidance in how to accomplish defining a dynamic map for a reference type with CSVHelper.

Set to default instead delete cascade

I am making code first entity framework database model, and I am struggeling with cascade delete. There are my simple classes:
public class User {
[Key()]
public int Id {get; set;}
public string Name {get; set;}
public int CampaignId {get; set;}
[ForeignKey("CampaignId")]
public virtual Campaign Campaign {get; set;}
}
public class Campaign {
[Key()]
public int Id {get; set;}
public string Description {get; set;}
public virtual List<User> Users {get; set;}
public Campaign() {
Users = new List<User>();
}
}
The basic idea is to assign one campaign to every user. When I delete campaign which is assigned by user:
internal static void DeleteCampaign(Campaign campaignToDelete) {
using (var context = new DatabaseContext()) {
context.Entry(campaignToDelete).State = EntityState.Deleted;
context.SaveChanges();
}
}
Users assigned to that campaign are deleted too. What I want is to not delete users, but assign them to first avaible campaign, or null. For some reason I cant do something like that:
internal static void DeleteCampaign(Campaign campaignToDelete) {
using (var context = new DatabaseContext()) {
for (int i = 0; i < campaignToDelete.Users.Count; i++) {
campaignToDelete.Users[i].Campaign = context.Campaigns.ElementAt(0);
}
context.Entry(campaignToDelete).State = System.Data.Entity.EntityState.Deleted;
context.SaveChanges();
}
}
Because I am getting error:
An unhandled exception of type 'System.ObjectDisposedException' occurred in EntityFramework.dll
Additional information: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
So how can I avoid that?
Lazy loading should be enabled by default when using virtual.
This may be helpful:
How to disable cascade delete for link tables in EF code-first?
1) What kind of object do you pass to the DeleteCampaign method?
I think that is one of your entity framwork proxy models, which was queried by another database context.
You access in your for-loop the linked User object, which could not be loaded because the context doesn't exist anymore.
for (int i = 0; i < campaignToDelete.Users.Count; i++) {
Don't mix objects of different database contexts.
Better way is, that you pass the ID of the Campaign to the DeleteCampaign method and then you have to query the campaign in the new database context.
After that you can do all operations in one using statement (= the same database context).
static void DeleteCampaign(int idOfCampaignToDelete)
{
using (var context = new DatabaseContext())
{
var campaignToDelete = context.Campaigns.FirstOrDefault(c => c.Id == idOfCampaignToDelete);
for (int i = 0; i < campaignToDelete.Users.Count; i++)
{
campaignToDelete.Users[i].Campaign = context.Campaigns.ElementAt(0);
}
context.Entry(campaignToDelete).State = System.Data.Entity.EntityState.Deleted;
context.SaveChanges();
}
}
2) You cannot use ElementAt(0) in a LINQ to Entities query.
Use .FirstOrDefault().
campaignToDelete.Users[i].Campaign = context.Campaign.FirstOrDefault();
3) Make the CampaignId in your User class nullable. Otherwise you cannot have Users without Campaigns, because the Foreign Key would not be nullable.
public int? CampaignId {get; set;}
Now your code should work.

automapper with runtime mapping configuration

In my ASP.NET MVC application I need to implemenet mapping from one object to another with some kind of UI for mapping configuration in runtime, so the user can define mapping "on the go". Is there any libraries that supports such functionality?
Description
This is objects in my application. I need to somehow allow user to configure mapping of this objects via UI during application runs. For exmaple some kind of page in my application where user will be able to define mapping in simple way like so map Amout of OrderDTO to Order Qty and later without application recompile change this mapping for exmaple for ExactAmmount
//Object in DAL
public class Order
{
public int Id {get; set;}
public string Name {get; set;}
public decimal Qty {get; set;}
//Lots of other fields
}
//Object from XSD generation (for example)
public class OrderDTO
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Ammout {get; set;}
public decimal VAT {get; set;}
public decimal ExactAmmount {get; set;}
//Lots of other fields
}
Note: for legacy reasons I based this answer on AutoMapper 4.2.1 instead of the current 5.x version. The overall approach should be similar with the new version.
It is possible to create different mapping configurations and different mappers within a program. Also, it is possible to create member mappings by member names (string) instead of lambda expressions. However, some static type information is still necessary (as far as my example goes).
See the following example of a profile, that prepares a custom mapping based on property names:
class MemberProfile : Profile
{
private string from;
private string to;
public MemberProfile(string from, string to)
{
this.from = from;
this.to = to;
}
protected override void Configure()
{
this.CreateMap<Order, OrderDTO>()
.ForMember(to, c => c.MapFrom<decimal>(from));
}
}
This could be extended to support different source property types and a collection of custom mappings instead of a single one.
Usage example:
var order = new Order() { Id = 1, Name = "Test", Qty = 0.5m };
var conf1 = new MapperConfiguration(c => c.AddProfile(new MemberProfile("Qty", "Ammout")));
var conf2 = new MapperConfiguration(c => c.AddProfile(new MemberProfile("Qty", "ExactAmmount")));
var res1 = conf1.CreateMapper().Map<OrderDTO>(order);
var res2 = conf2.CreateMapper().Map<OrderDTO>(order);
For res1, Qty is mapped to Ammout and for res2, Qty is mapped to ExactAmmount. Since the difference is described as string property names, it should be possible to let the user influence this configuration.

How to set this from Entity Framework using Linq

A while back, I fell into the fat controller trap when I was first working with MVC. My first app used EF4 to make all the models I needed. I just put all my logic into my controller actions. While it worked, it's definitely not the best practice way. To do it the right way I started trying to build my models based on my EF objects in an effort to follow the skinny controller concept.
I've run into a roadblock in trying to find the best way to populate my models. Is there a way to run a LINQ query and have it populate your model without having to iterate through the properties to set to another class?
Something like this:
// from EF model built from database
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
public class MyObjectModel : MyEFObject
{
private Entities _data = new Entities();
public MyObjectModel(int? id)
{
if(id.HasValue) // get an existing record
{
this = _data.MyEFObjects.Where(m => m.ID.Equals(id)).Single();
// or populate right out of the query
_data.MyEFObjects.Where(m => m.ID.Equals(id))
.Select(o => new {
this.ID = o.ID,
this.Name = o.Name,
this.Title = o.Title
});
}
else
{
// set defaults for a new MyObjectModel
}
}
public void Save()
{
// takes the current object and saves changes
}
}
I know you can add a function to the EF Entity object, but I like having the option to Create or Update all tied up in one call (Save method). I don't see the point messing with a model if I have to essentially recreate what I already have from my EF Object. If I simply have a method on a class that accepts a populated object, the concept of a usable model for my views is negated.
Slauma is right. LINQ to Entities won't accept it. I tried a couple of versions of what was posted and I only found my self with a kludgy mess. I got it to the point where I could set instance values, but by then EF wouldn't register a change had been made and defeating the whole purpose. There may be a way to do this, but as of now, the steps to make it work seem to be overkill.
I ended up with something like this:
public class MyObjectModel : MyEFObject
{
public void Save(int? id, MyObjectModel model)
{
var data = new Entities();
MyEFObject foo;
if(id.HasValue)
{
foo = data.MyEFObjects.Where(e => e.ID.Equals(id.Value)).Single();
}
else
{
foo = new MyEFObject();
}
foo.Name = model.Name;
foo.Title = model.Title;
if(!id.HasValue)
{
data.MyEFObjects.AddObject(foo);
}
data.SaveChanges();
}
}
I didn't want to have to work with two instances of my model, but it works and I have my lean controller action.
What you could do is have a domain model, ef model and and adapter. I think this keeps the code pretty clean and nicely separates the mapping logic.
//Domain model to decouple from EF
public class MyObjectModel
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Auto generated Entity Framework class
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Adapter responsible for mapping your data to your domain model
public class MyObjectModelAdapter : MyEFObject
{
public MyObjectModelAdapter(MyEFObject entity)
{
if(entity != null)
{
this.ID = entity.ID;
this.Name = entity.Name;
this.Title = entity.Title;
}
else
{
// set defaults for a new MyObjectModel
}
}
}
Then the basic usage would be:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x));
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)));
If you specifically require a list of MyObjectModel then you could do the following:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x) as MyObjectModel);
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)) as MyObjectModel;
Of course you don't want to chain your entity context together like that, it is just to show usage.

Categories

Resources