I have tried to Eagerly load all the data related to an entity, but I still have a problem regarding the recusive properties like this one :
public class Node : BaseAbstractEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[ForeignKey("TypeId")]
public virtual NodeType Type { get; set; }
public int? TypeId { get; set; }
[ForeignKey("ParentId")]
public virtual Node Parent { get; set; }
public int? ParentId { get; set; }
public ICollection<Node> Children { get; set; }
}
I am using it in this method :
public async Task<object> JustGetAsync(Type type, JObject value, DbContext context)
{
int id = 0;
if (value != null && value["id"] != null)
id = Int32.Parse(value["id"].ToString());
if (id != 0)
return await context.FindAsync(type, id);
var TypeSet = (IQueryable<object>) context.GetType()
.GetMethod("Set")
.MakeGenericMethod(type)
.Invoke(context, null);
return await TypeSet.Include(context.GetIncludePaths(type)).ToListAsync();
}
the get IncludePaths is a code that I found here enter link description here that helps to eager all the properties :
public static IQueryable Include(this IQueryable source, IEnumerable navigationPropertyPaths)
where T : class
{
return navigationPropertyPaths.Aggregate(source, (query, path) => query.Include(path));
}
public static IEnumerable<string> GetIncludePaths(this DbContext context, Type clrEntityType)
{
var entityType = context.Model.FindEntityType(clrEntityType);
var includedNavigations = new HashSet<INavigation>();
var stack = new Stack<IEnumerator<INavigation>>();
while (true)
{
var entityNavigations = new List<INavigation>();
foreach (var navigation in entityType.GetNavigations())
{
if (includedNavigations.Add(navigation))
entityNavigations.Add(navigation);
}
if (entityNavigations.Count == 0)
{
if (stack.Count > 0)
yield return string.Join(".", stack.Reverse().Select(e => e.Current.Name));
}
else
{
foreach (var navigation in entityNavigations)
{
var inverseNavigation = navigation.FindInverse();
if (inverseNavigation != null)
includedNavigations.Add(inverseNavigation);
}
stack.Push(entityNavigations.GetEnumerator());
}
while (stack.Count > 0 && !stack.Peek().MoveNext())
stack.Pop();
if (stack.Count == 0) break;
entityType = stack.Peek().Current.GetTargetType();
}
}
Related
I want to compare all of my list of generic T property value to my local variable searchText.
i already try:
x.GetType().GetProperties().All(props => props.GetValue(x).ToString().ToLower().Contains(searchText.ToLower()))
and i get error : NullReferenceException: Object reference not set to an instance of an object.
here my full method :
protected List<T> ProcessCollection<T>(List<T> lstElements, IFormCollection requestFormData, Func<T, IComparable> getProp)
{
string searchText = string.Empty;
Microsoft.Extensions.Primitives.StringValues tempOrder = new[] { "" };
if (requestFormData.TryGetValue("search[value]", out tempOrder))
{
searchText = requestFormData["search[value]"].ToString();
}
var skip = Convert.ToInt32(requestFormData["start"].ToString());
var pageSize = Convert.ToInt32(requestFormData["length"].ToString());
if (requestFormData.TryGetValue("order[0][column]", out tempOrder))
{
var columnIndex = requestFormData["order[0][column]"].ToString();
var sortDirection = requestFormData["order[0][dir]"].ToString();
tempOrder = new[] { "" };
if (requestFormData.TryGetValue($"columns[{columnIndex}][data]", out tempOrder))
{
var columName = requestFormData[$"columns[{columnIndex}][data]"].ToString();
if (pageSize > 0)
{
var prop = GetProperty<T>(columName);
if (sortDirection == "asc")
{
return lstElements.Where(x=>x.GetType().GetProperties().All(props => props.GetValue(x).ToString().ToLower().Contains(searchText.ToLower()))
.Skip(skip).Take(pageSize).OrderBy(b => prop.GetValue(b)).ToList();
}
else
return lstElements
.Where(x => getProp(x).ToString().ToLower().Contains(searchText.ToLower()))
.Skip(skip).Take(pageSize).OrderByDescending(b => prop.GetValue(b)).ToList();
}
else
return lstElements;
}
}
return null;
}
this is how i call my method :
var listItem = ProcessCollection<Jtabel>(temp,requestFormData,x=>x.Name);
the temp that i pass to method already filled
and this is the class type that i pass to this method
public class Jtabel : BaseModel
{
public string Creator { get; set; }
public string Name { get; set; }
public int SO { get; set; }
public int SOD { get; set; }
public int SAP { get; set; }
public int BA { get; set; }
public int Invoice { get; set; }
public int EPD { get; set; }
public double DP { get; set; }
}
i will try to explain more detail as much i can, so i want to get all of my property from Jtabel class to my ProcessCollection where inside the method all of Jtable property will test each element that's contain searchText.
i need to add some data in OptionRoleTable:
public class OptionRole
{
public int Id { get; set; }
public int RoleId { get; set; }
public int OptionsId { get; set; }
public virtual Role Role { get; set; }
public virtual Options Options { get; set; }
}
and this is Options Tabel:
public partial class Options
{
public int Id { get; set; }
public string OptionName { get; set; }
public string RouteFunctionName { get; set; }
public string Icon { get; set; }
public virtual ICollection<OptionRole> OptionRoles { get; set; }
}
i must check data not exist in OptionRole , when i using this code for add data in OptionRole :
public async Task<Options> findOptionsId(int optionId)
{
return await _option.FirstOrDefaultAsync(x => x.Id == optionId);
}
public async Task<bool> AddorUpdateOptions(int optionId, IList<int> selectedRoleValue)
{
List<OptionVM> optionVMs = new List<OptionVM>();
List<int> currentOptionValue = new List<int>();
var optionRole = await findOptionsId(optionId);
if (optionRole == null)
{
return false;
}
foreach (var item in selectedRoleValue)
{
var findRole = await _roleManager.FindByIdAsync(item);
var findOPR = optionRole.OptionRoles.FirstOrDefault(x => x.OptionsId== optionId && x.RoleId==item);
if (findOPR != null)
{
currentOptionValue.Add(item);
}
}
if (selectedRoleValue == null)
{
selectedRoleValue = new List<int>();
}
var newOptionRole = selectedRoleValue.Except(currentOptionValue).ToList();
foreach (var opRole in newOptionRole)
{
var findRole = await _roleManager.FindByIdAsync(opRole);
if (findRole != null)
{
optionRole.OptionRoles.Add(new OptionRole
{
OptionsId = optionRole.Id,
RoleId = findRole.Id
});
}
}
var removeOptionRole = currentOptionValue.Except(selectedRoleValue).ToList();
foreach (var remove in removeOptionRole)
{
var findOptionRole = _optionRoles.FirstOrDefault(x => x.Id == remove);
if (findOptionRole != null)
{
optionRole.OptionRoles.Remove(findOptionRole);
}
}
return Update(optionRole.OptionRoles);
}
I must have pass a class type of Options when i using this code . it show me this Error :
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.ICollection' to 'StoreFinal.Entities.Entities.Identity.OptionRole' StoreFinal.Services C:\Users\Mr-Programer\Desktop\New folder\StoreFinal\StoreFinal.Services\Contracts\Identity\Service\ApplicationOptionRoleManager.cs 97 Active
Error in this line : return Update(optionRole.OptionRoles);
whats the problem ? how can i solve this problem ?
Edit :
Update Method :
public virtual bool Update(T entity)
{
try
{
Entities.Attach(entity);
return true;
}
catch (Exception)
{
return false;
}
}
Look at the Update Method signature:
public virtual bool Update(T entity);
It accepts a param type T which should be One Entity - Why One Entity -- because Entities.Attach() accepts only 1 Object. While what you are passing to it is:
return Update(optionRole.OptionRoles);
Where OptionRoles is of type: ICollection<OptionRole> --
For understandings sake, Change it to
return Update(optionRole.OptionRoles[0]);
or
return Update(optionRole.OptionRoles.First());
And then share the result.
I'm creating a view model for a Customer entity in EF. My question is if I'm using the correct approach. I convert an entity property to a view model property. And, if what I need to return is a list I convert the properties for each object.
Is there a better way to do this serialization? I'm not asking about if convert an entity to a model is the correct approach. I'm not doing that, I just return what is needed. What I want to know is if is there a better way to serialize the entity to an object in a view model.
This is my view model:
public class CustomerModel
{
public int TotalRecords { get; set; }
public int CUSTOMER_KEY { get; set; }
public decimal CCUSTID { get; set; }
public string CCNAME { get; set; }
public string ACCNOTES { get; set; }
public string CUSTPRCLEVEL_CODE { get; set; }
public string CUSTPRCLEVEL_CODE_Name { get; set; }
public DateTime LASTMODIFIEDDATE { get; set; }
public string LASTMODIFIEDBY { get; set; }
public static Customer FromModelToEntity(CustomerModel model)
{
Customer entity = new Customer();
entity.CUSTOMER_KEY = model.CUSTOMER_KEY;
entity.CCUSTID = model.CCUSTID;
entity.CCNAME = model.CCNAME != null ? model.CCNAME : null;
entity.ACCNOTES = model.ACCNOTES != null ? model.ACCNOTES : null;
entity.CUSTPRCLEVEL_CODE = model.CUSTPRCLEVEL_CODE != null ? model.CUSTPRCLEVEL_CODE : null;
entity.LASTMODIFIEDDATE = model.LASTMODIFIEDDATE;
entity.LASTMODIFIEDBY = model.LASTMODIFIEDBY != null ? model.LASTMODIFIEDBY : null;
return entity;
}
public static CustomerModel FromEntityToModel(Customer entity)
{
CustomerModel model = new CustomerModel();
model.CUSTOMER_KEY = entity.CUSTOMER_KEY;
model.CCUSTID = entity.CCUSTID;
model.CCNAME = entity.CCNAME != null ? entity.CCNAME : null;
model.ACCNOTES = entity.ACCNOTES != null ? entity.ACCNOTES : null;
model.CUSTPRCLEVEL_CODE = entity.CUSTPRCLEVEL_CODE != null ? entity.CUSTPRCLEVEL_CODE : null;
model.CUSTPRCLEVEL_CODE_Name = entity.CustomerPricingLevel != null ? entity.CustomerPricingLevel.DESCRIPTION : string.Empty;
model.LASTMODIFIEDDATE = entity.LASTMODIFIEDDATE;
model.LASTMODIFIEDBY = entity.LASTMODIFIEDBY != null ? entity.LASTMODIFIEDBY : null;
return model;
}
public static List<Customer> FromModelToEntity(List<CustomerModel> modelList)
{
List<Customer> entityList = new List<Customer>();
foreach (var item in modelList)
{
entityList.Add(CustomerModel.FromModelToEntity(item));
}
return entityList;
}
public static List<CustomerModel> FromEntityToModel(List<Customer> entityList)
{
List<CustomerModel> modelList = new List<CustomerModel>();
foreach (var item in entityList)
{
modelList.Add(CustomerModel.FromEntityToModel(item));
}
return modelList;
}
}
Not sure what sort of answer you are seeking.
You can shorten your code using LINQ though. (System.Linq)
Insead of the foreach, you can use a 1 liner:
So that this:
public static List<Customer> FromModelToEntity(List<CustomerModel> modelList)
{
List<Customer> entityList = new List<Customer>();
foreach (var item in modelList)
{
entityList.Add(CustomerModel.FromModelToEntity(item));
}
return entityList;
}
Turns into this:
public static List<Customer> FromModelToEntity(List<CustomerModel> modelList)
{
return modelList.Select(item => FromModelToEntity(item)).ToList();
}
I have a class:
internal class Paginated<T> where T : class
{
public List<T> data { get; set; }
public int total { get; set; }
public int page { get; set; }
public int per_page { get; set; }
public Paging paging { get; set; }
}
and in another class, I have method:
public T RequestAllPaginated<T>() where T : Paginated<AnyType> //AnyType???
{
var item = Request<T>();
//Get all data from paging property
if(item != null)
{
var i = item as Paginated<AnyType>; //AnyType???
var data = i.data;
}
return item;
}
T is always a Paginated<AnyType> type. The question is how can I determine in RequestAllPaginated method declaration and cast it later on?
Try this solution
public T RequestAllPaginated<T, TK>() where T : Paginated<TK> where TK : class
{
var item = Request<T>();
//Get all data from paging property
if(item != null)
{
var i = item as Paginated<TK>;
var data = i.data;
}
return item;
}
Alternative solution:
public Paginated<T> RequestAllPaginated<T>() where T : class
{
var item = Request<Paginated<T>>();
//Get all data from paging property
if(item != null)
{
var i = item as Paginated<T>;
var data = i.data;
}
return item;
}
I am using EF 5.0 Code First in a C# project. I have a base clase which the majority of my domain models derive from.
public abstract class AuditableModelBase
{
public Int32 CreatedByUserId { get; set; }
public DateTime CreatedDate { get; set; }
public virtual UserProfile CreatedByUserProfile { get; set; }
public Int32 UpdatedByUserId { get; set; }
public DateTime UpdatedDate { get; set; }
public virtual UserProfile UpdatedByUserProfile { get; set; }
public AuditableModelBase()
{
CreatedByUserId = 1;
CreatedDate = DateTime.UtcNow;
UpdatedByUserId = 1;
UpdatedDate = DateTime.UtcNow;
}
}
However, for every single entity I have to define the specific configurations to wire these relationships together.
// Relationships
this.HasRequired(amb => amb.CreatedByUserProfile).WithMany().HasForeignKey(amb => amb.CreatedByUserId).WillCascadeOnDelete(false);
this.HasRequired(amb => amb.UpdatedByUserProfile).WithMany().HasForeignKey(amb => amb.UpdatedByUserId).WillCascadeOnDelete(false);
I'm looking for a way to just declare one Configuration similar to the one directly above for the abstract base class instead of having to create an individual configuration file for each of my entities. I'd love to just have one file named "AuditableModelBaseMap.cs" which will have my configuration instead of "Entity1Map.cs", "Entity2Map.cs", "Entity3Map.cs", etc. especially since all of those files have the exact same code inside.
Any advice?
Thanks.
Try it like below but I didnt test it .However if I were you, I wouldnt design Audit tables this way
class AuditableModelBaseMap : EntityTypeConfiguration<AuditableModelBase>
{
public AuditableModelBaseMap ()
{
this.HasRequired(amb => amb.CreatedByUserProfile).WithMany().HasForeignKey(amb => amb.CreatedByUserId).WillCascadeOnDelete(false);
this.HasRequired(amb => amb.UpdatedByUserProfile).WithMany().HasForeignKey(amb => amb.UpdatedByUserId).WillCascadeOnDelete(false);
}
}
THIS IS MY WAY OF Doing AUDITING
public interface IEntity
{
int Id { get; set; }
}
public interface IAuditable : IEntity
{
string UpdatedBy { get; set; }
string CreatedBy { get; set; }
DateTime CreatedDate { get; set; }
DateTime UpdateDate { get; set; }
}
Now any entity which is auditable will implement this class your context will look the following
public class MYContext : DbContext, ILicensingContext
{
private readonly IAuditLogBuilder _auditLogBuilder;
public LicensingContext()
: this(new AuditLogBuilder())
{
}
private IDbSet<Device> Devices { get; set; }
private IDbSet<AuditLog> AuditLogs { get; set; }
public MyContext(IAuditLogBuilder auditLogBuilder)
{
_auditLogBuilder = auditLogBuilder;
}
/// <summary>
/// 1. Constructs the AuditLog objects from the context
/// 2. Calls SaveChanges to save the actual object modified
/// 3. It updates the Log objects constructed in step 1 to populate the IDs returned from the Db
/// 4. Saves the AuditLogs
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
var entries = ChangeTracker.Entries<IAuditable>().ToList();
_auditLogBuilder.UpdateAuditables(entries);
IEnumerable<AuditLog> auditLogEntities = _auditLogBuilder.ConstructAuditLogs(entries).ToList();
int countOfAffectedRecords = base.SaveChanges();
_auditLogBuilder.UpdateAuditLogs(auditLogEntities);
foreach (AuditLog auditLogEntity in auditLogEntities)
{
GetDbSet<AuditLog>().Add(auditLogEntity);
}
base.SaveChanges();
return countOfAffectedRecords;
}
public IDbSet<TEntity> GetDbSet<TEntity>() where TEntity : class
{
return Set<TEntity>();
}
}
public class AuditLogBuilder : IAuditLogBuilder
{
private string _username;
private string Username
{
get
{
if (HttpContext.Current != null && HttpContext.Current.User != null)
{
_username = HttpContext.Current.User.Identity.Name;
}
if (String.IsNullOrWhiteSpace(_username))
{
_username = "Service Consumer";
}
return _username;
}
}
public IEnumerable<AuditLog> ConstructAuditLogs(IEnumerable<DbEntityEntry<IAuditable>> auditableEntities)
{
var audits = new List<AuditLog>();
if (auditableEntities != null)
{
audits.AddRange(auditableEntities
.Where(
e =>
e.State == EntityState.Modified || e.State == EntityState.Added ||
e.State == EntityState.Deleted)
.SelectMany(GetAuditLogs));
}
return audits;
}
public void UpdateAuditLogs(IEnumerable<AuditLog> auditLogEntities)
{
foreach (AuditLog auditLog in auditLogEntities)
{
auditLog.RecordId = auditLog.Entity.Id;
auditLog.UpdatedBy = auditLog.Entity.UpdatedBy;
if (String.Equals(auditLog.PropertyName, "id", StringComparison.CurrentCultureIgnoreCase))
{
auditLog.NewValue = auditLog.Entity.Id.ToString(CultureInfo.CurrentCulture);
}
}
}
public void UpdateAuditables(IEnumerable<DbEntityEntry<IAuditable>> entries)
{
if (entries != null)
{
foreach (var entry in entries)
{
entry.Entity.UpdateDate = DateTime.UtcNow;
entry.Entity.UpdatedBy = Username;
if (entry.Entity.Id == 0)
{
entry.Entity.CreatedDate = DateTime.UtcNow;
entry.Entity.CreatedBy = Username;
}
}
}
}
private static IEnumerable<AuditLog> GetAuditLogs(DbEntityEntry<IAuditable> entry)
{
var audits = new List<AuditLog>();
string entityName = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
switch (entry.State)
{
case EntityState.Added:
audits.AddRange(entry.CurrentValues.PropertyNames.Select(propertyName =>
new AuditLog
{
EntityName = entityName,
CreateDate = DateTime.UtcNow,
NewValue =
entry.CurrentValues[
propertyName] != null
? entry.CurrentValues[
propertyName].ToString()
: String.Empty,
PreviousValue = String.Empty,
PropertyName = propertyName,
Entity = entry.Entity,
Action = Actions.Create.ToString()
}));
break;
case EntityState.Deleted:
audits.AddRange(entry.OriginalValues.PropertyNames.Select(propertyName =>
new AuditLog
{
EntityName = entityName,
CreateDate = DateTime.UtcNow,
NewValue = String.Empty,
PreviousValue =
entry.OriginalValues[
propertyName] != null
? entry.OriginalValues[
propertyName].ToString
()
: String.Empty,
PropertyName = propertyName,
Entity = entry.Entity,
Action = Actions.Delete.ToString()
}));
break;
case EntityState.Modified:
audits.AddRange(entry.OriginalValues.PropertyNames.
Where(
propertyName =>
!Equals(entry.OriginalValues[propertyName],
entry.CurrentValues[propertyName]))
.Select(propertyName =>
new AuditLog
{
EntityName = entityName,
CreateDate = DateTime.UtcNow,
NewValue =
entry.CurrentValues[propertyName] != null
? entry.CurrentValues[propertyName].ToString()
: String.Empty,
PreviousValue =
entry.OriginalValues[propertyName] != null
? entry.OriginalValues[propertyName].ToString()
: String.Empty,
PropertyName = propertyName,
Entity = entry.Entity,
Action = Actions.Update.ToString()
}));
break;
}
return audits;
}
}
Have you tried this?
public class AuditableModelBaseMap : EntityTypeConfiguration<AuditableModelBase>
{
public AuditableModelBaseMap()
{
this.HasRequired(amb => amb.CreatedByUserProfile).WithMany().HasForeignKey(amb => amb.CreatedByUserId).WillCascadeOnDelete(false);
this.HasRequired(amb => amb.UpdatedByUserProfile).WithMany().HasForeignKey(amb => amb.UpdatedByUserId).WillCascadeOnDelete(false);
}
}