Performance Entity Framework Code First - performance

I have a performance problem using code first and entity framework. I only want to read a simple mapping info which to up to 3 seconds.
// The enity
[Table("ResourceMappingEntity")]
public class ResourceMappingEntity
{
/// <summary>
/// Gets or sets the testing number.
/// </summary>
/// <value>
/// The testing number.
/// </value>
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(80)]
public string LocationNameOrIp { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(80)]
public string Resource { get; set; } //todo mb: noch nicht drin
[Column(TypeName = "varchar")]
[StringLength(80)]
public string App { get; set; } //todo mb: noch nicht drin
/// <summary>
/// Gets or sets the created at.
/// </summary>
/// <value>
/// The created at.
/// </value>
[Column(TypeName = "datetime2")]
public DateTime CreatedAt { get; set; }
}
//the query
using (var ctx = new OsmaTestingContextFactory().Create())
{
ctx.Configuration.ProxyCreationEnabled = false;
var two = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
var dif = two - one;
IEnumerable<string> res = await ctx.ResourceMappingEntityStorage.AsNoTracking()
.Where(
x => x.LocationNameOrIp == IPOrName)
.Select(y => y.Resource)
.ToListAsync();
var three = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
var dif2 = three - two;
if (res.Count() != 1)
{
throw new Exception("Can not find a specific resouce");
}
return res.First();
}
// I also set IsUnicode to false....
Any ideas?
Hope for help or alternative solutions?! Should be ok in a few milliseconds like in SQL managment studio
Is there a good or standrad way to test the performance of ef?
Thx
Marcus

Related

Build dynamic select using LINQ with nested class

I am trying to create a dynamic select builder that includes also nested class.
Basically I have entity class DB then DTO like in the following classes
/// <summary>
/// Base entity class
/// </summary>
public abstract class BaseEntity
{ }
/// <summary>
/// EF Schema entity
/// </summary>
public class AMOS_AMOSUSER : BaseEntity
{
public decimal USERID { get; set; }
public decimal? SUPERIORID { get; set; }
public decimal? EMPLOYEEID { get; set; }
public virtual AMOS_AMOSUSER SUPERIOR { get; set; }
public string LOGINID { get; set; }
public string NAME { get; set; }
public string COMMENT1 { get; set; }
public decimal ACCOUNTDISABLED { get; set; }
public DateTime? LASTLOGIN { get; set; }
}
/// <summary>
/// DTO base for all dtos
/// </summary>
public abstract class DTO_BASE
{
}
/// <summary>
/// DTO amos user base
/// </summary>
public class DTO_AMOSUSER_BASE : DTO_BASE
{
public decimal USERID { get; set; }
public string LOGINID { get; set; }
public string NAME { get; set; }
}
/// <summary>
/// DTO AMOS User
/// </summary>
public class DTO_AMOSUSER : DTO_AMOSUSER_BASE
{
public decimal? SUPERIORID { get; set; }
public virtual DTO_AMOSUSER_BASE SUPERIOR { get; set; }
}
Here below code for testing and creating dynamic select.
public static class TestDynamicSelect
{
public static void TestDynamicSelectDTO()
{
List<AMOS_AMOSUSER> users = new List<AMOS_AMOSUSER>();
PopulateUsers(users);
var q = users.AsQueryable().Select(DynamicSelectGenerator2<AMOS_AMOSUSER, DTO_AMOSUSER>(typeof(DTO_AMOSUSER).GetProperties().Select(p => p.Name)));
var cc = q.ToArray();
foreach (var item in cc)
{
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
}
Console.ReadLine();
}
public static Expression<Func<T, TSelect>> DynamicSelectGenerator1<T, TSelect>(string fields)
{
return DynamicSelectGenerator2<T, TSelect>(fields.Split(','));
}
/// <param name="fields">
/// Format1: "Field1"
/// Format2: "Nested1.Field1"
/// Format3: "Field1:Field1Alias"
/// </param>
public static Expression<Func<T, TSelect>> DynamicSelectGenerator2<T, TSelect>(IEnumerable<string> fields)
{
string[] EntityFields;
if (fields == null || fields.Count() == 0)
// get Properties of the T
EntityFields = typeof(T).GetProperties().Select(propertyInfo => propertyInfo.Name).ToArray();
else
EntityFields = fields.ToArray();
// input parameter "x"
var xParameter = Expression.Parameter(typeof(T), "x");
// new statement "new Data()"
var xNew = Expression.New(typeof(TSelect));
// create initializers
var bindings = EntityFields
.Select(x =>
{
string[] xFieldAlias = x.Split(':');
string field = xFieldAlias[0];
string[] fieldSplit = field.Split('.');
if (fieldSplit.Length > 1)
{
// original value "x.Nested.Field1"
Expression exp = xParameter;
foreach (string item in fieldSplit)
exp = Expression.PropertyOrField(exp, item);
// property "Field1"
PropertyInfo member2 = null;
if (xFieldAlias.Length > 1)
member2 = typeof(TSelect).GetProperty(xFieldAlias[1]);
else
member2 = typeof(T).GetProperty(fieldSplit[fieldSplit.Length - 1]);
// set value "Field1 = x.Nested.Field1"
var res = Expression.Bind(member2, exp);
return res;
}
// property "Field1"
var mi = typeof(T).GetProperty(field);
PropertyInfo member;
if (xFieldAlias.Length > 1)
member = typeof(TSelect).GetProperty(xFieldAlias[1]);
else
member = typeof(TSelect).GetProperty(field);
// original value "x.Field1"
if (member != null)
{
if (mi != null)
{
if (typeof(BaseEntity).IsAssignableFrom(mi.PropertyType))
{
List<string> props = new List<string>();
mi.PropertyType.GetProperties().ToList().ForEach(p => {
if (member.PropertyType.GetProperties().Any(c => c.Name.Equals(p.Name, StringComparison.Ordinal)))
props.Add(p.Name);
});
Type ex = typeof(TestDynamicSelect);
MethodInfo mm = ex.GetMethod("DynamicSelectGenerator2");
MethodInfo miConstructed = mm.MakeGenericMethod(mi.PropertyType, member.PropertyType);
var expr = (LambdaExpression)miConstructed.Invoke(null, new object[] { props });
// Probably here is not correct
return Expression.Bind(member, Expression.TypeAs(expr, member.PropertyType));
}
else
{
var xOriginal = Expression.Property(xParameter, mi);
return Expression.Bind(member, xOriginal);
}
}
}
//return Expression.Constant(GetDefault(mi.PropertyType));
throw new Exception("No property to bind");
}
);
var b = bindings.Where(x => x != null && xNew.Type.GetProperties().Any(p => p.Name.Equals(x.Member.Name, StringComparison.OrdinalIgnoreCase)));
// initialization "new Data { Field1 = x.Field1, Field2 = x.Field2 }"
var xInit = Expression.MemberInit(xNew, b);
// expression "x => new Data { Field1 = x.Field1, Field2 = x.Field2 }"
var lambda = Expression.Lambda<Func<T, TSelect>>(xInit, xParameter);
return lambda;
}
}
I can't populate correctly the nested property SUPERIOR which is always null.
Basically what I am trying to do is to populate DTO classes from an Entity class using property name comparison.
Please help.

EF Core Linq Query Syntax

I'm trying to replicate a view inside EF. The original view used a UNION operator so have split my initial query here in tow to better match. Having some issues working out my syntax. I am trying to query the groups, get their primary contact details. Also get all vehicles and their linked groups. I believe I have specified the ContactLink requirement correctly in the first query.
[BindProperty]
public IList<OrgChartNode> OrgChartNodes { get; set; }
public JsonResult OnGet(string OrgCode)
{
IList<OrgChartNode> OrgChartGroups = _db.Groups
.Include(g => g.ContactLinks)
.ThenInclude(gtc => gtc.Contact)
.Include(g => g.Organisation)
.Where(g => g.OrgCode.Equals(OrgCode))
.Where(g => g.ContactLinks.Any(cl => cl.LinkTypeId == 1))
.Select(g => new OrgChartNode
{
Id = g.Id,
Name = g.Name,
TierId = g.TierId,
ParentGroupId = g.ParentGroupId,
OrgName = g.Organisation.Name,
OrgCode = g.OrgCode,
ContactName = g.ContactLinks.**Contact**.Name,
ContactEmail = g.ContactLinks.**Contact**.Phone,
ContactPhone = g.ContactLinks.**Contact**.Email,
ContactId = g.ContactLinks.**Contact**.ContactId,
})
.OrderByDescending(g => g.TierId)
.ThenBy(g => g.Name)
.AsNoTracking()
.ToList();
IList<OrgChartNode> OrgChartUnits = _db.Units
.Include(u => u.GroupLinks)
.Include(u => u.Organisation)
.Where(u => u.OrgCode.Equals(OrgCode))
.Select(u => new OrgChartNode
{
Id = u.NodeId,
Name = u.Name,
TierId = 0,
ParentGroupId = u.GroupLinks.**GroupId**,
OrgName = u.Organisation.Name,
OrgCode = u.OrgCode,
ContactName = "",
ContactEmail = "",
ContactPhone = "",
ContactId = 0,
})
.OrderBy(u => u.Name)
.AsNoTracking()
.ToList();
OrgChartNodes = OrgChartGroups.Concat(OrgChartUnits)
.ToList();
return new JsonResult(OrgChartNodes);
}
The four Contact fields have been marked wih **. They have red intellisense lines in Visual Studio. Looks like it cat follow to Contact, despite it being ThenInclude() above. So does the GroupId in the second query. Hovering over the acronym/aliases tells me they appear to be the correct classes.
Listed below are the three data classes. You can see the Navigation properties. Are they configured correctly?
How can I include the contact details in my .Select() call?
Group.cs
[Table("Report_Group")]
public class Group
{
[Key, Required, Column("GroupId")]
public int Id { get; set; }
[Required, MaxLength(5)]
public string OrgCode { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
public int TierId { get; set; }
public int? ParentGroupId { get; set; }
public int? CostCenter { get; set; }
[Required]
public int ExcludeFromAlertStats { get; set; }
[Required]
public int GroupTypeId { get; set; }
[ForeignKey("ParentGroupId")]
public virtual Group Parent { get; set; }
[ForeignKey("OrgCode")]
public virtual Organisation Organisation { get; set; }
[ForeignKey("TierId")]
public virtual Tier Tier { get; set; }
[ForeignKey("GroupTypeId")]
public virtual GroupType GroupType { get; set; }
[InverseProperty("GroupId")]
public virtual IList<GroupToUnitLink> UnitLinks { get; set; }
[InverseProperty("GroupId")]
public virtual IList<GroupToContactLink> ContactLinks { get; set; }
}
GroupToContactLink.cs
This classes key is set using fluent in OnModelCreating() as it is a composite key.
[Table("Report_Link_Group_to_Contact")]
public class GroupToContactLink
{
public GroupToContactLink()
{
}
public GroupToContactLink(int contactId, int groupId, int linkTypeId)
{
this.ContactId = contactId;
this.GroupId = groupId;
this.LinkTypeId = linkTypeId;
}
[Required]
public int ContactId { get; set; }
[Required]
public int GroupId { get; set; }
[Required]
public int LinkTypeId { get; set; }
[ForeignKey("ContactId")]
public virtual Contact Contact { get; set; }
[ForeignKey("GroupId")]
public virtual Group Group { get; set; }
[ForeignKey("LinkTypeId")]
public virtual ContactLinkType LinkType { get; set; }
}
Contact.cs
[Table("Report_Contact")]
public class Contact
{
/// <summary>
/// Primary Key for Contact in the database
/// </summary>
[Key, Column("ContactId")]
public int Id { get; set; }
/// <summary>
/// Foreign Key indicating <see cref="Data.Organisation"/>
/// </summary>
[Required, StringLength(5)]
public string OrgCode { get; set; }
/// <summary>
/// Name of Contact
/// </summary>
[Required, StringLength(100)]
public string Name { get; set; }
/// <summary>
/// Phone number of contact. Needs to be in +614 format for SMS to work
/// </summary>
[StringLength(12)]
public string Phone { get; set; }
/// <summary>
/// Email Address for Contact
/// </summary>
[StringLength(255), EmailAddress]
public string Email { get; set; }
/// <summary>
/// Navigation property to <see cref="Data.Organisation"/>
/// </summary>
[ForeignKey("OrgCode")]
public virtual Organisation Organisation { get; set; }
[InverseProperty("ContactId")]
public virtual IList<GroupToContactLink> GroupLinks { get; set; }
}

OutputCache varying by a complex object property

I have a controller action that receives a complex object as a parameter, I need the OutputCache to vary by one of the properties of this complex object. Is this possible? How?
if you have a model like
public class person{
public string Name {get;set;}
public string location {get;set;}
}
and in the (strongly typed)view you have a form
#model Person
#Html.BeginForm(){
#Html.TextBoxFor(x=>x.Name)
#Html.TextBoxFor(x=>x.location)
}
and you submit the form to an ActionResult savePerson, with varying signature like
public ActionResult savePerson(Person p){
// p.Name
// p.location
}
or
public ActionResult savePerson(string Name, string location){
}
therefore i think if you annotate the ActionResult like
[OutputCache(Duration=3600, VaryByParam="Name")]
public ActionResult savePerson(Person p)
{
//
return View();
}
it will do for you, or if you have a complex model like
public class person{
public string Name {get;set;}
public Location loc {get;set;}
}
public class Location{
public string address
}
try
[OutputCache(Duration=3600, VaryByParam="Person.Location.address")]
public ActionResult savePerson(Person p)
{
//
return View();
}
I had the same requirement as above and came up with a slightly different approach
The class
/// <summary>
/// This class is used to encapsulate search filters for monitor graphs
/// </summary>
public class DatacarMonitorSearchCriteriaModel
{
public int? SynergyCode { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime StartDate { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime EndDate { get; set; }
/// <summary>
/// Filter to apply
/// </summary>
public IEnumerable<int> Countries { get; set; }
public DatacarMonitorSearchCriteriaModel()
{
Countries = new List<int>();
}
}
OutputCacheComplexAttribute
/// <summary>
/// <para>
/// An instance of this class mimic the behaviour of OutputCacheAttribute but for complex objects.
/// </para>
/// <para>
/// It allows to cache the output of any action that takes complex objects
/// </para>
/// </summary>
public class OutputCacheComplexAttribute : OutputCacheAttribute
{
private readonly Type[] _types;
private string _cachedKey;
/// <summary>
/// Initializes a new instance of the <see cref="OutputCacheComplexAttribute"/> class.
/// </summary>
/// <param name="types">Types that this attribute will lookup for in QueryString/Form data and store values in cache.</param>
/// <exception cref="System.ArgumentOutOfRangeException">type;type cannot be null</exception>
public OutputCacheComplexAttribute(params Type[] types)
{
if (types == null)
{
throw new ArgumentOutOfRangeException("type", "type cannot be null");
}
_types = types;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
StringBuilder sbCachedKey = new StringBuilder();
if (filterContext.HttpContext.Request.Url != null)
{
string path = filterContext.HttpContext.Request.Url.PathAndQuery;
IDictionary<string, object> parameters = filterContext.ActionParameters;
//we need to compute a cache key which will be used to store the action output for later retrieval
//The cache key scheme is
// {url}:{key 1}:{value};[{key 2}:{value 2}[; ... {key n}:{value n}]];
// where :
// - url is the url of the action that will be executed
// - key n is the name of the n-th parameter
// - value n is the value of the n-th parameter as json string.
foreach (KeyValuePair<string, object> kv in parameters)
{
var kv1 = kv;
if (kv.Value != null && _types.AtLeastOnce(t => t.IsInstanceOfType(kv1.Value)))
{
sbCachedKey = sbCachedKey.AppendFormat("{0}:{1};",kv.Key,
JsonConvert.SerializeObject(kv.Value, Formatting.None, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
}
}
_cachedKey = String.Format("{0}:{1}:{2}", GetType().Name, path, sbCachedKey.ToString());
}
if (!String.IsNullOrWhiteSpace(_cachedKey) && filterContext.HttpContext.Cache[_cachedKey] != null)
{
filterContext.Result = (ActionResult)filterContext.HttpContext.Cache[_cachedKey];
}
else
{
base.OnActionExecuting(filterContext);
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!String.IsNullOrWhiteSpace(_cachedKey))
{
filterContext.HttpContext.Cache.Add(_cachedKey, filterContext.Result, null,
DateTime.UtcNow.AddSeconds(Duration), Cache.NoSlidingExpiration,
CacheItemPriority.Default, null);
}
base.OnActionExecuted(filterContext);
}
}
Attribute usage
[OutputCacheComplex(typeof(DatacarMonitorSearchCriteriaModel), Duration = OutputCacheDurationInSeconds, Location = OutputCacheLocation.Server)]
public async Task<JsonNetResult<DatacarMonitorDetailModel>> ReadMonitorDetailsJson([DataSourceRequest] DataSourceRequest request, DatacarMonitorSearchCriteriaModel criteria)
{
//some really complicated code here
}
with this new attribute, you can specify which type[s] to use for caching and the cache key will be computed based on values of each its properties.
For object, just that work fine:
[OutputCache(VaryByParam = "*", Duration = 60)]

returning anonymous type as list of string linq

I'm having one of those days....
Here's my class:
/// <summary>
/// Represent a trimmed down version of the farms object for
/// presenting in lists.
/// </summary>
public class PagedFarm
{
/// <summary>
/// Gets or sets Name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets Slug.
/// </summary>
public string Slug { get; set; }
/// <summary>
/// Gets or sets Rating.
/// </summary>
public int Rating { get; set; }
/// <summary>
/// Gets or sets City.
/// </summary>
public string City { get; set; }
/// <summary>
/// Gets or sets Crops.
/// </summary>
public List<string> Crops { get; set; }
}
Here's my meagre attempt to parse my parent Farm entity into the PagedFarm class.
int pageNumber = page ?? 1;
// Get a list of all the farms and hostels
var farms =
this.ReadOnlySession.Any<Farm>(x => x.Deleted == false).Select(
x =>
new PagedFarm
{
Name = x.Name,
Slug = x.Slug,
Rating = x.Rating,
City = x.City.Name,
// The line below doesn't work.
Crops = x.Crops.Select(c => new { c.Name })
.OrderBy(c => c.Name)
})
.ToPagedList(pageNumber, this.PageSize);
My error message:
Cannot implicitly convert type
System.Linq.IOrderedEnumerable<AnonymousType#1> to
System.Collections.Generic.List<string>. An explicit conversion
exists (are you missing a cast?)
Tried casting but no joy. What am I doing wrong?
I think you probably want:
Crops = x.Crops.Select(c => c.Name).OrderBy(name => name).ToList()
Try:
Crops = x.Crops.Select(crop => crop.Name) // Sequence of strings
.OrderBy(name => name) // Ordered sequence of strings
.ToList() // List of strings

nop commerce automapper exception, missing type map configuration or unsupported mapping

I have tried to debug and find where the mismatch is coming from but I can not. Any ideas about where to look?
here is the model
public class PatientModel : BaseNopEntityModel
{
public PatientModel()
{
AvailableStates = new List<SelectListItem>();
}
[NopResourceDisplayName("Patient.Fields.FirstName")]
[AllowHtml]
public string FirstName { get; set; }
[NopResourceDisplayName("Patient.Fields.LastName")]
[AllowHtml]
public string LastName { get; set; }
[NopResourceDisplayName("Patient.Fields.MiddleName")]
[AllowHtml]
public string MiddleName { get; set; }
[NopResourceDisplayName("Patient.Fields.RoomNumber")]
[AllowHtml]
public string RoomNumber { get; set; }
[NopResourceDisplayName("Patient.Fields.HospitalName")]
[AllowHtml]
public string HospitalName { get; set; }
[NopResourceDisplayName("Patient.Fields.StateProvince")]
public int? StateProvinceId { get; set; }
[NopResourceDisplayName("Patient.Fields.StateProvince")]
[AllowHtml]
public string StateProvince { get; set; }
[NopResourceDisplayName("Patient.Fields.City")]
[AllowHtml]
public string City { get; set; }
[NopResourceDisplayName("Patient.Fields.ZipPostalCode")]
[AllowHtml]
public string ZipPostalCode { get; set; }
public IList<SelectListItem> AvailableStates { get; set; }
public bool FirstNameDisabled { get; set; }
public bool LastNameDisabled { get; set; }
public bool MiddleNameDisabled { get; set; }
public bool RoomNumberDisabled { get; set; }
public bool HospitalNameDisabled { get; set; }
public bool StateProvinceDisabled { get; set; }
public bool CityDisabled { get; set; }
public bool ZipPostalCodeDisabled { get; set; }
}
and here is the entity that it is trying to map to
public class Patient : BaseEntity, ICloneable
{
/// <summary>
/// Gets or sets the first name
/// </summary>
public virtual string FirstName { get; set; }
/// <summary>
/// Gets or sets the last name
/// </summary>
public virtual string LastName { get; set; }
/// <summary>
/// Gets or sets the middle name
/// </summary>
public virtual string MiddleName { get; set; }
/// <summary>
/// Gets or sets the patient room number
/// </summary>
public virtual string RoomNumber { get; set; }
public virtual string HospitalName { get; set; }
/// <summary>
/// Gets or sets the state/province identifier
/// </summary>
public virtual int? StateProvinceId { get; set; }
/// <summary>
/// Gets or sets the state/province
/// </summary>
public virtual StateProvince StateProvince { get; set; }
/// <summary>
/// Gets or sets the city
/// </summary>
public virtual string City { get; set; }
/// <summary>
/// Gets or sets the zip/postal code
/// </summary>
public virtual string ZipPostalCode { get; set; }
public virtual DateTime CreatedOnUtc { get; set; }
public object Clone()
{
var pat = new Patient()
{
FirstName = this.FirstName,
LastName = this.LastName,
MiddleName = this.MiddleName,
RoomNumber = this.RoomNumber,
HospitalName = this.HospitalName,
StateProvince = this.StateProvince,
StateProvinceId = this.StateProvinceId,
City = this.City,
ZipPostalCode = this.ZipPostalCode,
CreatedOnUtc = DateTime.UtcNow
};
return pat;
}
}
and mapper where the issue occurs
public static PatientModel ToModel(this Patient entity)
{
return Mapper.Map<Patient, PatientModel>(entity);
}
That means you never called Mapper.CreateMap<>() for those two types.
I found a way of getting it to work correctly the only problem was I had to change
public static PatientModel ToModel(this Patient entity)
{
return Mapper.Map<Patient, PatientModel>(entity);
}
and remove the mapper and do it manually to map the patient entitiy to the model.

Resources