How to populate one extra property in a .Select - LINQ [duplicate] - c#

This question already exists:
How to solve Npgsql.NpgsqlOperationInProgressException: A command is already in progress
Closed 3 years ago.
I'm using my Map method to create DTO object from my context class Company and it looks like this:
private CompDTO Map(Company company)
{
return new CompDTO()
{
Id = company.Id,
Title = company.Title,
ParentCompanyId = company.ParentCompanyId,
};
}
CompDTO looks like this:
public class CompDTO
{
public long Id { get; set; }
public string Title { get; set; }
public long? ParentCompanyId { get; set; }
public bool HasChildrens { get; set; }
}
I'm using it like this, basically receiving list of companies and calling another Map method which would create DTO object from my company objects and main issue for me is that Company class does not contain HasChildrens property, so I have to populate it somehow, and I couldn't do it where I'm maping other props because there I dont have access to a companies list.
private IEnumerable<CompDTO> Map(IEnumerable<Company> companies)
{
// Mapping all properties except HasChildrens because it does not exist in Company object so I decided to map it later
var result = companies.Select(c => Map(c));
// Here I wanted to return all previously mapped objects + I would like to add to each object HasChildren property, but obliviously my syntax is not good:
return result.Select(c => new { c, c.HasChildrens = companies.Any(cc => cc.ParentCompanyId == c.Id) });
}
I'm retrieving error: Invalid anonymous type declarator.
I've tried to add HasChildrens like this also:
return result.Select(c => {c.HasChildrens = companies.Any(cc => cc.ParentCompanyId == c.Id)});
But still issues..
Basically I simply want to add HasChildrens for each my Mapped DTO and return it as it was added in Map method.
Any kind of help would be great!
Thanks

The return type of your method private IEnumerable<CompDTO> Map(IEnumerable<Company> companies) is IEnumerable<CompDTO>
So the issue is that you're returning an anonymous type rather than the expected CompDTO
Change return result.Select(c => new { ... }
to
return result.Select(c => new CompDTO {
Id = ...
Title = ...
ParentCompanyId = ...
HasChildrens = ...
})
EDIT:
The actual question is:
How do I set the property HasChildrens in the CompDTO while converting from db classes to dto classes
I'd say that the most common way to solve that is to pass in the value while converting:
private CompDTO Map(Company company, bool hasChildrens) {
return new CompDTO()
{
Id = company.Id,
Title = company.Title,
ParentCompanyId = company.ParentCompanyId,
HasChildrens = hasChildrens
};
}
You could also iterate the result after the fact and set the HasChildrens like so: (I wouldn't recommend this)
foreach(dto in result) {
dto.HasChildrens = ...
}
You could also insert the logic of obtaining the HasChildrens value inside of the Map method: (I wouldn't recommend this either)
private CompDTO Map(Company company, IEnumerable<Company> companies) {
return new CompDTO()
{
Id = company.Id,
Title = company.Title,
ParentCompanyId = company.ParentCompanyId,
HasChildrens = companies
.Any(c => c.ParentCompanyId == company.Id)
};
}

Related

Check which elements are on one list comparing to another list LINQ

I have two lists, one of all languages and another subset of languages that the site has, the idea is to return all the languages but change the property of a boolean if the element of the subset corresponds to the list of all languages.
DTO of language:
public class DTOLanguage
{
public bool HaveLanguage { get; set; }
public int IdLanguage { get; set; }
//Other properties...
}
Method that returns all languages:
public List<DTOLanguage> GetLanguages()
{
var result = repository.RepSite.GetLanguages().Select(x => new DTOLanguage
{
IdLanguage = x.IdLanguage,
CodName = x.CodName,
Name = x.Name
}).ToList();
return result;
}
Method that returns the subset of languages:
public List<DTOLanguage> GetLanguagesById(int idSite)
{
var result = repository.RepSite.GetLanguagesById(idSite).Select(x => new DTOLanguage
{
IdLanguage = x.IdLanguage
}).ToList();
return result;
}
The GetLanguagesById is called in the DataAccess layer, so what Im thinking is that this method should receive another parameter (what GetLanguages returns) and make some fancy LINQ there.
I know that I can filter (example):
SubsetOfLanguages.Where(lg => lg.IdLanguage == AllLanguagesItem.IdLanguage)
{
AllLanguagesItem.HaveLanguage = True;
}
But Im not really sure as how it should be.
Thanks in advance.
You could use Contains extension method this way:
var languages=GetLanguages();
var subsetids=repository.RepSite.GetLanguagesById(idSite).Select(x =>x.IdLanguage);//Select just the id value
foreach(var l in languages.Where(l=>subsetids.Contains(l.IdLanguage)))
{
l.HaveLanguage = true;
}
You could do this:
var allLanguages = GetLanguages();
var subset = SubsetOfLanguages
.Where(lg => allLanguages.Any(a => lg.IdLanguage == a.IdLanguage))
.ToArray();
foreach(var item in subset)
{
item.HaveLanguage = True;
}

How to use mapper.Map inside MapperConfiguration of AutoMapper?

I need to map an object to another one using AutoMapper. The tricky question is how can I access an instance of the mapper (instance of IMapper) inside of the mapping configuration or inside of a custom type converter?
The code below does not work, however it is an example of what I would like to achieve - please notice the mapper.Map calls and assume that mappings Customer => CustomerDto and Customer => DetailedCustomerDto are defined.
var config = new MapperConfiguration(
cfg => cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing(o => {
return o.Type == 1
? mapper.Map<Customer, CustomerDto>(o.Customer)
: mapper.Map<Customer, DetailedCustomerDto>(o.Customer)
})
);
The client part is:
var mapper = config.CreateMapper();
var orderDto = mapper.Map<Order, OrderDto>(order);
The simplified version of objects I want to map is:
public class Order
{
public int Type { get; set; }
public Customer Customer { get; set; }
}
public class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
public class OrderDto
{
public CustomerDto Customer { get; set; }
}
public class CustomerDto
{
public long Id { get; set; }
}
public class DetailedCustomerDto : CustomerDto
{
public string Name { get; set; }
}
As you see from the code above, based on the value of Order.Type, the mapper should map the property Order.Customer to different targets. As one target (DetailedCustomerDto) inherits from the other one (CustomerDto) it becomes a bit tricky.
Please notice that usage of the obsolete and deprecated static method Mapper.Map is NOT an option.
As of AutoMapper 8.0 and up
The answer below for 5.1.1 still applies, but note that the use of ResolveUsing has been replaced with an overload of MapFrom, but the signature has otherwise remained consistent.
As of AutoMapper 5.1.1
You can get to the mapper using another overload of ResolveUsing with four parameters, fourth of which is ResolutionContext (context.Mapper):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing((order, orderDto, i, context) => {
return order.Type == 1
? context.Mapper.Map<Customer, CustomerDto>(order.Customer)
: context.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
Prior to AutoMapper 5.1.1
You can get to the mapper using another overload of ResolveUsing with two parameters, first of which is ResolutionResult (result.Context.Engine.Mapper):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing((result, order) => {
return order.Type == 1
? result.Context.Engine.Mapper.Map<Customer, CustomerDto>(order.Customer)
: result.Context.Engine.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
In addition to Evk's great answer, which helped me, if you need to do a mapping inside a mapping inside a config/profile that requires a custom constructor (i.e. the type has no default constructor), the following will work in v5.2.0:
CreateMap<Models.Job, Models.API.Job>(MemberList.Source);
CreateMap<StaticPagedList<Models.Job>, StaticPagedList<Models.API.Job>>()
.ConstructUsing((source, context) => new StaticPagedList<Models.API.Job>(
context.Mapper.Map<List<Models.Job>, List<Models.API.Job>>(source.ToList()),
source.PageNumber,
source.PageSize,
source.TotalItemCount));
In this example I'm mapping the X.PagedList custom collection type of one object type onto an equivalent collection of another object type. The first parameter to the lamdba expression is your source object, the second is your ResolutionContext from which you can access a mapper instance to map from.
I'm using Automapper 9 and the answers above didn't work for me.
Then for resolve my problem that is like yours I use .afterMap, like that:
public class AutoMapperOrder : Profile
{
public AutoMapperOrder()
{
CreateMap<Customer, CustomerDto>()
//...
CreateMap<Customer, DetailedCustomerDto>()
//...
CreateMap<Order, OrderDto>()
.AfterMap((src, dest, context) => {
dest.Customer = src.Type == 1
? context.Mapper.Map<Customer, CustomerDto>(src.Customer)
: context.Mapper.Map<Customer, DetailedCustomerDto>(src.Customer)
}
}
}
}
I hope to help somebody.

how to return value in self defined type in neo4jclient

I'm new to neo4jclient and i don't know how to return self defined type in neo4jclient.
i have the following cypher:
var result = client.Cypher
.Match("(u:User)-[:" + FriendRelation + "]->(friend:User)")
.Return((user, friend) => new RelationInDB(user.As<User>().id, friend.As<User>().id)).Results;
i want to return all id pair that have friend relation and i want to store two id in self defined class--RelationInDB, but i don't know how to write Return(i know the return above is wrong)
Can anyone help?
OK, there are 2 things you'll find which are causing you issues:
You can't return into the constructor of a class, you need to use a default constructor and property setting
Your return statement has (user, friend) => but your match statement has (u:User). Your return statement should be: (u, friend) =>
To that end:
var results = client
.Cypher
.Match("(u:User)-[:" + FriendRelation + "]->(friend:User)")
.Return((u, friend) => new RelationInDB{UserId = u.As<User>().Id, FriendId = friend.As<User>().Id}).Results;
My RelationInDB class is defined as:
public class RelationInDB
{
public int FriendId { get; set; }
public int UserId { get; set; }
public RelationInDB() { }
}
If you can't change your RelationInDB class and you need to use it as is, you will have to use an anonymous type for your return:
var results = client
.Cypher
.Match("(u:User)-[:" + FriendRelation + "]->(friend:User)")
.Return((u, friend) => new {UserId = u.As<User>().Id, FriendId = friend.As<User>().Id}).Results;
and parse afterwards with something like:
var relsInDb = results.Select(result => new RelationInDB(result.UserId, result.FriendId));

Inline method that support translation to sql

There is a model of a database that contains two entities related to foreign keys, such as
class Item
{
public int ID;
public string Name;
public int StatusID;
}
and
class Status
{
public int ID;
public string Name;
}
There is my own class
class MyClassFormat
{
public int ID;
public string Name;
public string Status;
}
Now I would like to create a method that returns a class of its own, something like that
MyClassFormat getTtem(this Item item)
{
return new MyClassFormat{ID = item.ID, Name = item.Name, Status = item.Statuses.Name}
}
The problem is that when I use this method, I get an exception that my method has no supported translation to SQL
Is it possible to create such a method which would be unwrapped its contents instead of calling this method?
Solved: Both answers are suitable for solving my problem, but the second one is the one I was looking for, thank you both
Either:
query
.Select(item => new
{
ID = item.ID,
Name = item.Name,
Status = item.Statuses.Name
})
.ToArray()
.Select(item => new MyClassFormat
{
ID = item.ID,
Name = item.Name,
Status = item.Status
});
or:
query
.ToArray()
.Select(item => getTtem(item));
The first way is longer to write, but it loads less data from database.
Anyway, you need to materialize query results (ToArray method in sample).
If your goal is to write code to reuse in multiple queries, you could factor out an expression like this:
static Expression<Func<Item, MyClassFormat>> ItemToClassFormat()
{
return item => new MyClassFormat
{
ID = item.ID,
Name = item.Name,
Status = item.Statuses.Name
}
}
This can be used similar to:
IQueryable<Item> query = ...;
var selector = ItemToClassFormat();
var results = query.Select(selector).ToList();

AutoMapper Map to different type based on an enum?

I'm starting to implement AutoMapper, first I managed to integrate it with Castle.Windsor, which I'm already using. Now I have a Post entity which I want to map to either a LinkPostModel or an ImagePostModel. Both inherit from PostModel
1) This is what I have so far:
public class PostModelFromPostEntityConverter : ITypeConverter<Post, PostModel>
{
private readonly IPostService postService;
public PostModelFromPostEntityConverter(IPostService postService)
{
if (postService == null)
{
throw new ArgumentNullException("postService");
}
this.postService = postService;
}
public PostModel Convert(ResolutionContext context)
{
Post post = (Post)context.SourceValue;
Link link = post.Link;
if (link.Type == LinkType.Html)
{
return new LinkPostModel
{
Description = link.Description,
PictureUrl = link.Picture,
PostId = post.Id,
PostSlug = postService.GetTitleSlug(post),
Timestamp = post.Created,
Title = link.Title,
UserMessage = post.UserMessage,
UserDisplayName = post.User.DisplayName
};
}
else if (link.Type == LinkType.Image)
{
return new ImagePostModel
{
PictureUrl = link.Picture,
PostId = post.Id,
PostSlug = postService.GetTitleSlug(post),
Timestamp = post.Created,
UserMessage = post.UserMessage,
UserDisplayName = post.User.DisplayName
};
}
return null;
}
}
Obviously the point in implementing AutoMapper is removing repeat code like this, so how am I supposed to map the common stuff, before adding my custom rules (such as the if-clause)
Ideally I'd want this to be something like:
public class PostModelFromPostEntityConverter : ITypeConverter<Post, PostModel>
{
[...]
public PostModel Convert(ResolutionContext context)
{
Post post = (Post)context.SourceValue;
Link link = post.Link;
if (link.Type == LinkType.Html)
{
return Mapper.Map<Post, LinkPostModel>(post);
// and a few ForMember calls?
}
else if (link.Type == LinkType.Image)
{
return Mapper.Map<Post, ImagePostModel>(post);
// and a few ForMember calls?
}
return null;
}
}
2) After this mapping is complete. I have a "parent" mapping, where I need to map an IEnumerable<Post> the following model:
public class PostListModel : IHasOpenGraphMetadata
{
public OpenGraphModel OpenGraph { get; set; } // og:model just describes the latest post
public IList<PostModel> Posts { get; set; }
}
So basically I'd need another TypeConverter (right?), which allows me to map the posts list first, and then create the og:model
I have this, but it feels kind of clunky, I feel it could be better:
public class PostListModelFromPostEntityEnumerableConverter : ITypeConverter<IEnumerable<Post>, PostListModel>
{
public PostListModel Convert(ResolutionContext context)
{
IEnumerable<Post> posts = (IEnumerable<Post>)context.SourceValue;
PostListModel result = new PostListModel
{
Posts = posts.Select(Mapper.Map<Post, PostModel>).ToList()
};
Post first = posts.FirstOrDefault();
result.OpenGraph = Mapper.Map<Post, OpenGraphModel>(first);
return result;
}
}
3) I didn't actually run the code yet, so another question comes to mind, and that is why aren't mappings strongly typed in converters?
IEnumerable<Post> posts = (IEnumerable<Post>)context.SourceValue;
where it could actually be
IEnumerable<Post> posts = context.SourceValue;
Trying to get Necromancer badge.
Nowadays this task can be solved much easier with using ConstructUsing function specifc fields should be filled in the provided action, but all the common fields will go to ForMember execution of the mapping. Collections in this case doesn't requires any additional logic/mapping configurations. Classes that has a property of type collection as well.
cfg.CreateMap<Post, PostModel>()
.ConstructUsing(p =>
{
switch (p.Type)
{
case LinkType.Html: return new LinkPostModel
{
Title = p.Description
// other specific fields
};
case LinkType.Image: return new ImagePostModel
{
// other specific fields
};
}
return null;
})
.ForMember(x => x.PostId, m => m.MapFrom(p => p.Id));
cfg.CreateMap<PostList, PostListModel>();

Categories