Inline method that support translation to sql - c#

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();

Related

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

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)
};
}

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 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));

Linq using StartsWith always empty

I have a simple List with dummy data as follows:
List<Organisation> list = new List<Organisation>();
list.Add(new Organisation() { LogoUrl = "/images/logos/Blade.png", OrganisationId = 1, OrganisationName = "Blade" });
list.Add(new Organisation() { LogoUrl = "/images/logos/Torn.png", OrganisationId = 2, OrganisationName = "Torn" });
When I run the linq query:
var results = from org in OrganisationsController.GetDummyList()
where org.OrganisationName.StartsWith(searchString)
select org;
It always returns an Empty result. In this case the searchString is specified by the user and the example would be "Tor".
Using different variations like 'where org.OrganisationName == searchString' where the search string is Torn works. But StartsWith never works.
Any ideas where I'm going wrong?
EDIT:
From Jon's code I changed my code to look as follows:
public JsonResult Search(string searchString)
{
//create json result object
JsonResult data = new JsonResult();
var list = OrganisationsController.GetDummyList();
//query the list
var results = from org in list
where org.OrganisationName.ToLower().Contains(searchString.ToLower())
select org;
if (results.Any())
{
System.Diagnostics.Debug.Write("found");
}
//setup the data
data.Data = results;
//return the data
return Json(data, JsonRequestBehavior.AllowGet);
}
Note: I changed the StartsWith to Contains, but both are giving me similary problems.
One of my organisations is called 'Absa'. Here's the really strange thing when I fire up the app for the first time putting in 'bsa' returns nothing, I then enter 'Absa' and it returns a good result. Then I entered 'bsa' again just to double check and it returned Absa which it didn't in the first test. Why would the result not work at first then work later?
Thanks,
Jacques
Unable to reproduce. It works fine for me:
using System;
using System.Collections.Generic;
using System.Linq;
class Organisation
{
public string LogoUrl { get; set; }
// Removed redundant Organisation prefixes
public int Id { get; set; }
public string Name { get; set; }
}
class Test
{
static void Main()
{
// Used collection initializer for sanity
var list = new List<Organisation>
{
new Organisation { LogoUrl = "Blade.png", Id = 1, Name = "Blade" },
new Organisation { LogoUrl = "Torn.png", Id = 2, Name = "Torn" },
};
string searchString = "Tor";
var query = from org in list
where org.Name.StartsWith(searchString)
select org;
// Nicer version:
// var query = list.Where(org => org.Name.StartsWith(searchString));
Console.WriteLine(query.Count()); // 1
}
}
Work out the difference between your code and my code to find out what's wrong.
In particular, you've shown code using List<T>, which means LINQ to Objects. If your real code uses LINQ to SQL or Entity Framework, that could easily affect things.

Get list of related objects whose type is in array of types

I have a function that (via ajax) I pass a Guid and a comma delimited string of the types of objects I would like to return . I'm having trouble building a link statement that only returns the desired types. I'm struggling with how to build the query to check if string[] relatedTypes matches rw.GetType().Name. Or perhaps there's a better way.
Here's the Model...
public abstract class WebObject : IValidatableObject
{
public WebObject()
{
this.Id = Guid.NewGuid();
RelatedTags = new List<Tag>();
RelatedWebObjects = new List<WebObject>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public virtual ICollection<WebObject> RelatedWebObjects { get; set; }
public IList<Guid> RelatedWebObjectIds { get; set; }
}
And here's my function
public JsonResult GetRelatedWebObjectsByWebObject(Guid id, string relatedWebObjectTypes)
{
JsonResult result = new JsonResult();
Guid webSiteId = db.WebObjects.Find(id).WebSiteId;
string[] relatedTypes = relatedWebObjectTypes.Split(',');
var resultData = (from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
where rw.GetType().Name.Contains(relatedTypes)
select rw.Id).ToList();
result.Data = resultData;
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}
Are you looking for something like:
var relatedTypes = new HashSet<string>(relatedWebObjectTypes);
var resultData = (from w in db.WebObjects
where w.Id == id
&& relatedTypes.SetEquals
(w.RelatedWebObjects.Select(rwo => rwo.GetType().Name))
select w.RelatedWebObjectIds).ToList();
Although I would say that it isn't good practice to use a collection of simple type names in this manner. Are you sure you couldn't use a Type[] or similar here?
It's not clear from your question what exactly do you want, but I think it's this:
from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
where relatedWebObjectTypes.Contains(rw.GetType().Name)
select rw.Id
This selects all the items from WebObjects with the correct Id (I guess there should be only one, but it does not matter to the query). And for each of them, get the RelatedWebObjects whose type's name is in relatedWebObjectTypes. And for each of those, get their Id.
You would need to refactor a bit, instead of passing in the name of the types as string, you should pass the actual type then use the linq operator for OfType(Of relatedType)
The MSDN Article gives a simple example that should have you on your way.
A little late, but here's what I ended up going with...
public JsonResult GetRelatedWebObjectsByWebObject(Guid id, string relatedWebObjectTypes)
{
JsonResult result = new JsonResult();
Guid webSiteId = db.WebObjects.Find(id).WebSiteId;
List<string> relatedTypes = new List<string>(relatedWebObjectTypes.Split(','));
var resultData = (from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
select rw).ToList();
result.Data = resultData.Where(w => relatedTypes.Contains(w.GetType().BaseType.Name) == true).Select(w => new { Id = w.Id, Type = w.GetType().BaseType.Name }).ToList();//w.Id).Select(w => w.GetType().BaseType.Name).ToList();
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}

Categories