How to create the function using Expression linq - c#

I have the following class
public class ProdutoTipo : IAuditable
{
public Guid ID { get; set; }
public string Nome { get; set; }
public string MiniNome { get; set; }
public string Descricao { get; set; }
public string Link { get; set; }
public int? Ordem { get; set; }
public virtual Foto ImagemExibicao { get; set; }
public virtual ICollection<ProdutoCategoria> Categorias { get; set; }
public DateTime CreatedAt { get; set; }
public string CreatedBy { get; set; }
public DateTime? UpdatedAt { get; set; }
public string UpdatedBy { get; set; }
public bool PaginaInicial { get; set; }
public ProdutoTipo() { ID = Guid.NewGuid(); }
}
I need a function that search the repository and returns true or false
But this search can be using any field of the class!
As far as I arrived
public bool Existe<TProperty, TComparer>(Expression<Func<ProdutoTipo, TProperty>> entityExpression, TComparer valor)
{
return Repository.ProdutoTipos.Any(p => /*entityExpression == valor ?????*/);
}
Would like to use the function like this ...
Existe(p => p.Nome, "Value to comparer!");
Thank you all!

I think you're looking for
Func<ProdutoTipo, TProperty> getter = entityExpression.Compile();
Repository.ProdutoTipos.Any(p => getter(p).Equals(valor));
But you might as well do this:
public bool Existe<TProperty, TComparer>(Expression<Func<ProdutoTipo, bool>> expression)
{
return Repository.ProdutoTipos.Any(expression);
}
And call:
Existe(p => p.Nome == "Value to comparer!");

Try:
public bool Existe<TProperty, TComparer>(Expression<Func<ProdutoTipo, TProperty>> entityExpression, TComparer valor)
{
entityExpression.Compile()(Repository.ProdutoTipos);
}

Related

EF6 - Many-to-One Relationship not working

I have Products, Sub products, and more tables. You can see in the code, relationship not working I want it Product Class relationship with SubProduct but always the collection count is 0.
Product Class:
[Key]
public int Id { get; set; }
public bool Status { get; set; } = true;
public string StockCode { get; set; }
public int StockDecrease { get; set; }
public string Name { get; set; }
public int Amount { get; set; }
public int Desi { get; set; }
public string Barcode { get; set; }
public long Gtin { get; set; }
public string InvoiceName { get; set; }
public string EInvoiceName { get; set; }
public string Subtitle { get; set; }
public byte Kdv { get; set; }
public virtual Category Category { get; set; }
public string Description { get; set; }
public virtual ICollection<SubProduct> SubProducts { get; set; }
public virtual ICollection<ProductVariant> ProductVariants { get; set; }
Sub Product Class:
public int Id { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public string StockCode { get; set; }
public virtual ProductBrand Brand { get; set; }
public virtual Company Company { get; set; }
public Abstract.Marketplace Marketplace { get; set; }
public string Barcode { get; set; }
public string Title { get; set; }
public string SubTitle { get; set; }
public bool IsConnected { get; set; }
public decimal Price { get; set; }
public decimal PriceDiscount { get; set; }
public string Description { get; set; }
public virtual ICollection<SubProductVariant> SubProductVariants { get; set; }
Repository Base:
public async System.Threading.Tasks.Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> filter)
{
await using var context = new TContext();
return await context.Set<TEntity>().Where(filter).SingleOrDefaultAsync();
}
Make sure to add using System.Data.Entity; to get the version of Include that takes in a lambda.
using System.Data.Entity;
query.Include(x => x.SubProducts)
and for more use ThenInclude or Include extention methods.
To define a method on the repository for this, you can use this example:
public static IQueryable<TSource> GetIQueryableWithIncludes<TSource>(Expression<Func<TSource, object>>[] includeProperties, IQueryable<TSource> result)
{
var newResult = result;
if (includeProperties.Any())
{
foreach (var includeProperty in includeProperties)
{
newResult = newResult.Include(includeProperty);
}
}
return newResult;
}
You can now pass a list of lamba expression like p => p.SubProjects to specify what you want to include.
You can further hide this by making an GetAll method that hides these includes from the outside user of your Domain
I would suggest to first study more about how to handle related entities.
You basically need to tell EF to load them in.
See documentation
Simplest example would something like this:
// Load all products.
var products= context.Products
.Include(b => b.SubProducts)
.ToList();
I solved with .Include() thanks for helping.
public async System.Threading.Tasks.Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> filter, Expression<Func<TEntity,object>> include=null)
{
await using var context = new TContext();
return await context.Set<TEntity>().Where(filter).Include(include).SingleOrDefaultAsync(filter);
}

Including children of children in C# Generic Repository EF

I am facing a slight problem and hope you could help, basically I would like to get children of children in Generic repository pattern as I have relationship table with multi-multi relationship
My Repository method looks like that:
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includes)
{
var query = _entities.Where(predicate).AsQueryable();
if (includes != null)
{
query = includes.Aggregate(query, (current, include) => current.Include(include));
}
return query;
}
public async Task<IQueryable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includes)
{
return await Task.Run(() => Find(predicate, includes));
}
My model:
Product:
public class Product : BaseEntity<long>
{
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Barcode { get; set; }
public int ShelfLife { get; set; }
public int Weight { get; set; }
public bool HasAllergens { get; set; }
[ForeignKey("Id")]
public int CustomerId { get; set; }
public virtual ICollection<ProductIngredient> ProductIngredient { get; set; }
}
Ingredient:
public class Ingredient : BaseEntity<long>
{
[MaxLength(100)]
public string Name { get; set; }
[ForeignKey("Id")]
public int CustomerId { get; set; }
public virtual ICollection<ProductIngredient> ProductIngredient { get; set; }
}
Relationship:
public class ProductIngredient : BaseEntity<long>
{
[ForeignKey("Id")]
public long? ProductId { get; set; }
[ForeignKey("Id")]
public long? IngredientId { get; set; }
}
What I'd like to achieve is to populate my ProductDto with ProductData and List of ingredients, my current ProductDto looks like:
public class ProductDto
{
public long Id { get; set; }
public DateTime CretedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
public int ShelfLife { get; set; }
public int Weight { get; set; }
public bool HasAllergens { get; set; }
public int CustomerId { get; set; }
public IList<IngredientDto> Ingredients { get; set; }
}
I've found that I can use "ThenInclude" to include children of children, just don't know how to implement this to generic repository.
What I can do so far is just take a children then which for example I'm doing like that:
var results = await _productsRepository.FindAsync(p => p.Id == id, p => p.ProductIngredient);
Any help much appreciated.
Thanks!

Strip all values from C# objects using Reflection

I have the following method which is used to retrieve all values as strings from an object using reflection. The object can have IEnumerables within them and I also want to retrieve these values. A list of ignore fields also needs to be taken into account so that those field's values are not returned.
public static IEnumerable<string> StringContent(this object obj, IEnumerable<string> ignoreProperties = null)
{
Type t = obj.GetType();
foreach (var prop in t.GetProperties())
{
if (ignoreProperties != null && ignoreProperties.Contains(field.Name))
{
continue;
}
var value = prop.GetValue(obj);
if (value != null)
{
if (value is IEnumerable<object>)
{
foreach (var item in (IEnumerable<object>)value)
{
foreach (var subValue in item.StringContent())
{
yield return subValue.ToString();
}
}
}
else
{
yield return value.ToString();
}
}
}
}
This method does work perfectly and gives me the correct result. However, I need to speed it up as much as possible because this is performed a lot of times.
Does anybody have any suggestions?
Thanks in advance!
** EDIT **
Example Test Case:
[TestMethod]
public void StringContent()
{
Project project = projectA;
List<string> ignoreFields = new List<string>() { "SalesEngineer", "CreationDate" };
var result = project.StringContent(ignoreFields);
Assert.IsTrue(result.Count() == 26);
}
Project Object:
public class Project : IEntity
{
public Project()
{
Products = new List<ProjectProducts>();
}
public int Id { get; set; }
public DateTime CreationDate { get; set; }
public string SalesEngineer { get; set; }
public string SalesEngineerEmail { get; set; }
public int? TeamId { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Originator { get; set; }
public string ContactName { get; set; }
public string MainClient { get; set; }
public string Contractor { get; set; }
public string ContractorContactName { get; set; }
public string ContractorLocation { get; set; }
public string Wholesaler { get; set; }
public string WholesalerContactName { get; set; }
public string WholesalerLocation { get; set; }
public float EstimatedValue { get; set; }
public float CalculatedValue {
get { return EstimatedValue/Convert.ToSingle(Currency != null ? Currency.Rate : (decimal)1.0); }
}
public int Probability { get; set; }
public int SectorId { get; set; }
public int TypeId { get; set; }
public string StatusCode { get; set; }
public string LostTo { get; set; }
public int ReasonId { get; set; }
public string SecondaryEngineer { get; set; }
public float SplitPercentage { get; set; }
public DateTime ExpectedOrder { get; set; }
public DateTime? RequiredOnSiteBy { get; set; }
public bool LightingDesignRequired { get; set; }
public string ReasonForLightingDesign { get; set; }
public DateTime? DesignRequiredBy { get; set; }
public DateTime? FollowUp { get; set; }
public string Comments { get; set; }
public int CurrencyId { get; set; }
public bool Void { get; set; }
public string AttachmentFolder { get; set; }
public virtual Currency Currency { get; set; }
public virtual Reason Reason { get; set; }
public virtual ProjectStatus Status { get; set; }
public virtual ProjectType Type { get; set; }
public virtual Sector Sector { get; set; }
public virtual ICollection<ProjectProducts> Products { get; set; }
public virtual Team Team { get; set; }
public object Key
{
get { return Id; }
}
}
You can use stringify package.
It exists in Nuget.
You can Hide parameters with Hidden attribute.
You can print every object with a.stringify();

Map a class which inherits a list of objects to a similar class

In my project I need to map objects from the external systems to DTOs. The object I want to map is:
public class PriceLists : List<PriceList> { }
I get the idea of mapping properties within the class but having difficulty finding a solution for this case. My DTO will preferably be "identical" to this source class to make it as simple as possible for the moment:
public class PriceListsDTO : List<PriceListDTO> { }
Is there a simple solution or do I need to refactor my DTO object?
Thanks.
Edit: I have tried creating mapping for a list of Price lists without success regarding this problem.
Mapper.Initialize(cfg => { cfg.CreateMap<PriceList>, <PriceListDTO>(); });
Mapper.Initialize(cfg => { cfg.CreateMap<IList<PriceList>, IList<PriceListDTO>>(); });
Edit2:
public class PriceList
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public int Id { get; set; }
public Nullable<Guid> ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public Nullable<DateTime> StartDate { get; set; }
public int Type { get; set; }
}
public class PriceListDTO
{
public string Agreement { get; set; }
public CurrencyViewModel Currency { get; set; }
public string Description { get; set; }
public DateTime? EndDate { get; set; }
public int Id { get; set; }
public Guid? ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public int Type { get; set; }
}
And the Currency class and DTO only contains string properties.
From the code you've given, you never actually told AutoMapper to associate the DTO with the model class. If you call Initialize twice, the second will REMOVE any previous mappings. Try updating your configuration to do the following:
Mapper.Initialize( cfg => {
cfg.CreateMap<PriceList, PriceListDTO>()
.ReverseMap();
// Not sure if this is required if you already have the model/dto map
cfg.CreateMap<IList<PriceList>, IList<PriceListDTO>>();
cfg.AssertConfigurationIsValid();
});
public class PriceList
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public int Id { get; set; }
public Nullable<Guid> ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public Nullable<DateTime> StartDate { get; set; }
public int Type { get; set; }
}
public class PriceListDTO
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public DateTime? EndDate { get; set; }
public int Id { get; set; }
public Guid? ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public int Type { get; set; }
}
after that try automapper.mapper.createmap it
will work for you otherwise you need to use formember method to map
properties of currency with currencyviewmodel one by one because
object are different to each other just try with it. hope it will help
for you . Thanks

How to convert one generic list to another

public static List<IndianAppStore_GetAllAppsByLanguage_ResultCache> GetAllApps(bool initialized, string language)
{
List<IndianAppStore_GetAllAppsByLanguage_ResultCache> objApp = new List<IndianAppStore_GetAllAppsByLanguage_ResultCache>();
List<IndianAppStore_GetAllAppsByLanguage_Result> objApps = new List<IndianAppStore_GetAllAppsByLanguage_Result>();
if (initialized == false)
{
var t = ListCopy(objApps, x => (IndianAppStore_GetAllAppsByLanguage_ResultCache)x); // Error
objApp = admin.getAllAppsByLanguage(language).ToList();
}
else
{
}
}
public static List<TResult> ListCopy<TSource, TResult>(List<TSource> input, Func<TSource, TResult> convertFunction)
{
return input.Select(x => convertFunction(x)).ToList();
}
My Class
public class IndianAppStore_GetAllAppsByLanguage_ResultCache
{
public long AppId { get; set; }
public string AppName { get; set; }
public string AppDisplayName { get; set; }
public string AppDetails { get; set; }
public string AppImageURL { get; set; }
public byte[] AppImageData { get; set; }
public long CategoryId { get; set; }
public Nullable<long> SubCategoryId { get; set; }
public string AppCreatedBy { get; set; }
public System.DateTime AppCreatedOn { get; set; }
public string AppModifiedBy { get; set; }
public Nullable<System.DateTime> AppModifiedOn { get; set; }
public Nullable<bool> isDeleted { get; set; }
public Nullable<bool> isPromotional { get; set; }
public string GenderTarget { get; set; }
public Nullable<long> CountryId { get; set; }
public Nullable<long> StateId { get; set; }
public Nullable<long> AgeLimitId { get; set; }
public Nullable<int> AppMinAge { get; set; }
public Nullable<int> AppMaxAge { get; set; }
}
I am trying to convert one generic class to another but getting this error
IndianAppStore_GetAllAppsByLanguage_Result and IndianAppStore_GetAllAppsByLanguage_ResultCache are different types and you cannot cast the first type to the other as you are doing in this statement:
var t = ListCopy(objApps, x => (IndianAppStore_GetAllAppsByLanguage_ResultCache)x);
If the types have the same structure you should probably just have one instead of two types. Otherwise you will have to copy the data from the first type to the other. E.g.:
var t = ListCopy(objApps, x => new IndianAppStore_GetAllAppsByLanguage_ResultCache {
AppId = x.AppId,
AppName = x.AppName,
...
});
This becomes tedious very quickly and one option is to use a library like AutoMapper to automate the process.

Categories

Resources