I have a simple test solution which consists of two projects (a 'business' layer and a Data Access layer) using Catel to tie the two together - works fine, no problems.
However, have been reading about how useful AutoMapper can be for helping to move data around such a setup by allowing easy population of DTO's and decided to give it a look...that's when my problems started!
I'm using Entity Framework 6.1, VS 2013 Express for Desktop and accessing a SQL Server Express 14 db - no problems with data retrieval and data displays correctly in my views.
AutoMapper was added using NuGet.
In order to use AutoMapper I've set up the following in my App.xaml.cs
private void InitializeAutomapper()
{
Mapper.CreateMap<Result, ResultDto>();
Mapper.AssertConfigurationIsValid();
}
This code is the first item called inside my 'OnStartup'.
A service in my business layer makes a call to the Data Access layer and retrieves a list of Result entites.
Subsequently, I take a single entity from this list and use that in the AutoMapper mapping call.
I'm trying to populate a resultDTO from this single entity, using the following
Result res = ResultList.First();
ResultDto resultDTO = Mapper.Map<Result, ResultDto>(res);
'res' is correctly populated with data but resultDTO is filled with the default values for the individual data types (in = 0, string = null, DateTime = {01/01/0001 00:00:00}) ie; no values are mapped from the source to the destination.
There are References in both projects to AutoMapper and AutoMapper.Net and no errors are raised - it just doesn't work as advertised...
I'm not slagging off the software, just asking what I'm doing wrong!
I realise there isn't much code to work on here but, in truth, what is posted here is pretty much all I've added to try out AutoMapper. I can see, conceptually how useful it could be - I just need to figure out how to make it happen so any help/comments gratefully received...:)
EDIT
#Andrew, as requested -
Result Class:
public partial class Result
{
public int Div { get; set; }
public System.DateTime Date { get; set; }
public string HomeTeam { get; set; }
public string AwayTeam { get; set; }
public int FTHG { get; set; }
public int FTAG { get; set; }
public string FTR { get; set; }
}
ResultDTO Class:
public class ResultDto
{
int Div { get; set; }
DateTime Date { get; set; }
string HomeTeam { get; set; }
string AwayTeam { get; set; }
int FTHG { get; set; }
int FTAG { get; set; }
string FTR { get; set; }
// Added tonight to try and get it to work
public ResultDto()
{
Div = 0;
Date = DateTime.Now;
HomeTeam = null;
AwayTeam = null;
FTHG = 0;
FTAG = 0;
FTR = null;
}
}
#stuartd, the following is used to retrieve the ResultList from which Result is obtained:
// Produce a list of DataLayer.Result entities.
var ResultList = (from x in dbContext.Results.Local
where x.HomeTeam == team.TeamName.ToString() || x.AwayTeam == team.TeamName.ToString()
orderby x.Date
select x).ToList();
Please note 'team.Teamname' is passed into the above from an external source - seems to be working fine.
So to sum up -
I produce ResultList as a list of Result entities.
Fill Result with the first entity in the list.
Try to map this Result entity to ResultDTO
Fail :(
Hope this helps!
By default, class members are declared private unless otherwise specified so the ResultDto properties aren't visible outside of the class.
public class ResultDto
{
int Div { get; set; }
....
}
needs to be
public class ResultDto
{
public int Div { get; set; }
....
}
AutoMapper can work out the type you are mapping from from the arguments provided. Try this:
ResultDto resultDTO = Mapper.Map<ResultDto>(res);
UPDATE
This is wrong, or at least won't help. We need to see the source and destination classes as mentioned in the comments.
Related
When using Entity Framework 6, how is the most efficient way to create an object or objects with additional data from other DbSet entities, when I have a DbContext or IQueryable<T>?
Here is some code:
If I have an Data class as follows:
public class Data
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string data { get; set; }
public int parentId { get; set; }
public int otherDataId { get; set; }
}
And an OtherData class as follows:
public class OtherData
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string data { get; set; }
}
In the Data class, the parentId is a foreign key reference to another Data object in the same DbSet, and the otherDataId is a foreign key reference to an OtherData object in a DbSet<OtherData>.
I would like to get all Data objects in the DbSet<Data>, with the additional DbSet data of the parent Data objects id and name and the OtherData object's id and name. I need this to be in one object to be sent from a webservice GET.
I am not sure on how to do this.
Do I need some code along the lines of:
var result = DbContext.Data.Select(x=> x...).Join(y=> y...) .. new { id = x.id... y.name.. }
Can I please have some help with this code?
You can use a join and project the result. In the below snippet CombinedData is a another class with 2 string fields Name and OtherName. You can also use a view but I think the Join is less work.
IQueryable<CombinedData> result = DbContext.Data.Join(
DbContext.Data.DbContext.OtherData,
outer => outer.OtherDataId,
inner => inner.Id),
(outer, inner) => new { Name = outer.Name, OtherName = inner.Name}
);
Depending on your overall architecture, this may be a good or a bad answer but often when faced with this in the past our teams would create a view in the database to combine the fields. Write your optimized query in the view and then treat it like any other table in your data layer.
You could accomplish the same end result using includes or joins or even writing out the expression in a cross-table query but in my opinion the view is the cleanest and most efficient method.
Based off of the example located here:
Multiple ViewModels in View
Can anyone show this example without adding the individual items but by showing a datasource. So for instance if my business Logic layer has the means to pull the customer address then my two models would be CustomerInfo & CustomerLocations - doing it this way I am having trouble with the last line shown (the .Add) .. I tried removing the ToList but either way it says I have invalid arguements - my ViewModel class looks exactly like the example.
var ccus = new List<ViewModel.CustomerInfo>();
var cloc = new List<ViewModel.CustomerLocations>();
var cust = new ViewModel.Customers();
var cI1 = new Business.CustomerLogic.BLCustomerAddress();
cI1.LoadCustomerAddress(decryConcept, decryBnumber, intCustid).ToList();
ccus.Add(cI1);
In the previous example he declares the code inline
var car1 = new Car
{
Id = 1,
Name = "Passat"
};
I want to replace this piece with a call to my Business Logic
I have no reference to the BusinesLogic model in the new ViewModel I have setup per the example and perhaps this is where I need to tie the two objects together. Here is my code for that piece.
public class ViewModel
{ public class Customers
{ public IEnumerable<CustomerInfo> CInfo { get; set; }
public IEnumerable<CustomerLocations> CLoc { get; set; }
}
public class CustomerInfo
{
public int CustomerID { get; set; }
public string AccountNo { get; set; }
public bool Active { get; set; }
public string Company { get; set; }
.........
ccus is of type List<ViewModel.CustomerInfo> so the add method expects a ViewModel.CustomerInfo but you are passing in cI1 which is of type Business.CustomerLogic.BLCustomerAddress. Calling ToList() won't do anything as you are not storing the result of LoadCustomerAddress, so turning the result into a list has no affect on anything.
I am converting a string into a list and then trying to use entity framework to insert it into a DB. The issue that I am having is that I don't know how to save the changes to the DB.
This is the code that I am trying to use and is where the string is converted to a list:
if (intCounter == 0)
{
return JsonConvert.DeserializeObject<List<foo>>(jsonString).Cast<T>().ToList();
}
Then in a seperate class below.
ConvertJson.Convert<CouncilEvent>(strResponseJSONContent, intCounter);
The Entity Framework Model that I am trying to use for the list.
namespace foo.Models
{
public partial class foo
{
public foo()
{
this.EventDates = new List<EventDate>();
}
public System.Guid foo_PK { get; set; }
public string EntityID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public bool Adult { get; set; }
}
}
The class foo contains properties that match those in the string.
It is this foo that I am then trying to insert into the DB. foo is also part of my Entity Framework model.
I have never used a list in this situation before and I thought it would just be a matter of using db.SaveChanges() but that doesn't seem to work. Where would I place the necessary lines of code such as using (db = new contextFoo) and db.SaveChanges(). Also do I need to add the items? I haven't because I thought I was already adding them to the class and therefore didn't need to do this manually?
db.SaveChanges() will only 'update' your database to what was changed. So, you need to add something to the database, and then call SaveChanges() for it to work.
You can loop the list to add the objects to the context, then call SaveChanges()...
var councilEvents = ConvertJson.Convert<CouncilEvent>(strResponseJSONContent, intCounter);
using (var db = new contextFoo())
{
foreach (var councilEvent in councilEvents)
{
db.CouncilEvents.Add(councilEvent);
}
db.SaveChanges();
}
I've got three classes.
Event > Workshop > Workshop Times
I'm currently looking for best way of inserting records into the Workshop Times, this is running through code first using ICollections.
Looking for something along the lines of this, but I know it doesn't work:
//Create connection
var db = new Context();
var Event = db.Events
.Include("Workshops")
.Include("Workshops.Times")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Event.Workshops.Add(new Workshop
{
Name = tbWorkshopName.Text,
Description = tbWorkshopDescription.Text,
Times.Add(new WorkshopTime{
//Information for times
})
});
db.SaveChanges();
Chopped down classes:
public class Workshops{
public int id { get; set; }
public string name { get; set; }
public ICollection<WorkshopTimes> Times{get;set;}
}
public class Events {
public int id { get; set; }
public string name { get; set; }
public ICollection<Workshops> WorkShops { get; set; }
}
public class WorkshopTimes {
public int id { get; set; }
public DateTime time { get; set; }
}
You are definitely on the right track with your query, however your include statements appear incorrect. From your model I would expect:
var Event = db.Events
.Include("WorkShops")
.Include("WorkShops.events")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Note this uses the property names not the types. This will ensure that the entities in the listed nav properties will be included in the result.
In addition you can use a lambda to do the same thing (but its typesafe)
Check out here for how to do a very similar scenario to yours:
EF Code First - Include(x => x.Properties.Entity) a 1 : Many association
or from rowan miller (from EF team)
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
And make sure you are using System.Data.Entities for lambda based includes ( Where did the overload of DbQuery.Include() go that takes a lambda? )
Please review my code. For every my Entity i've created a service class, where i put all the access methods for this entity.This method are doing the transformation from the Entities to my DTO classes. This methods are called from the Web layer or a bussines method. Am I doing this righth? Or should I do it differently ?
The service method:
public static IEnumerable<OsobaDto> GetNakupyByOsoba(Guid guid)
{
using (FinanceEntities finance = new FinanceEntities())
{
var osoby = from o in finance.OsobaSet
where o.Nakupy.Any(n => n.idnakupu == guid)
select new OsobaDto
{
Id = o.idosoba,
Meno = o.meno,
Priezvisko = o.priezvisko,
Prijem = o.prijem,
Nakupy = o.Nakupy.Select(n => new NakupDto
{
IdNakupu = n.idnakupu,
Cena = n.cena,
Datum = n.datum
})
};
return osoby;
}
}
And the DTO class
public class NakupDto
{
public Guid? IdNakupu
{
get;
set;
}
public Decimal Cena
{
get;
set;
}
public DateTime Datum
{
get;
set;
}
public IEnumerable<OsobaDto> Osoby
{
get;
set;
}
public OsobaDto Platil
{
get;
set;
}
Everything is good, but I have one suggestion. If you have a lot of DTO objects you shoud think about writing a general converter. It can be done using reflection and explicit conversion operators.
Keep in mind the query wont actually hit the database until you actually use the IEnumerable you are are returning (because of deferred execution). I'm not sure how that will work since you are disposing the FinanceEntities before you actually execute the query. Assuming that works, it looks fine to me.