how can separate result of object function? - c#

I have a LINQ query in function, like below code:
public object RetrieveFday(DateTime _dt)
{
var fp = from f in RSC.tbl_FoodPlan join food in RSC.tbl_Food
on f.FoodID equals food.FoodID
where f.Day == _dt
select new
{
FoodName= food.Name,
Fholiday= f.HoliDay
};
return fp;
}
now I call this function in other place, I want to get result and separate them to display every one in different label, when call the function and get result I cant read property of them:
var test = RetrieveFday(dt);
how can read the property in result that into test?

Anonymous types are not meant to use as a return types, so just create a new class to hold your projection data:
public class FoodNameAndHoliday
{
public string FoodName { get; set; }
public string Fholiday { get; set; }
}
And modify your RetrieveFday function to use your class in the select:
public IEnumerable<FoodNameAndHoliday> RetrieveFday(DateTime _dt)
{
var fp = from f in RSC.tbl_FoodPlan join food in RSC.tbl_Food
on f.FoodID equals food.FoodID
where f.Day == _dt
select new FoodNameAndHoliday
{
FoodName= food.Name,
Fholiday= f.HoliDay
};
return fp;
}
And you can then use your function like:
var test = RetrieveFday(dt);
foreach(var item in test)
{
DoSomethingWith(item.FoodName);
DoSomethingWith(item.Fholiday);
}

Related

Comparing two lists of class objects similar to a Diff Tool

Question moved here.
My requirement is to write a program that sort of mimics diff tools. Yes there are quite a few libraries and open source code that accomplishes this purpose, but I would like to write my own comparer.
Here's the starting point. I have a class called DataItem which looks like this:
public class DataItem
{
public DataItem() { }
public DataItem(string d, string v) { Data = d; Value = v; }
public string Data { get; set; }
public string Value { get; set; }
}
I have two lists of these class objects, let's call them PRE and POST and take some example values as follows. 'Data' part will be unique in a list.
preList: (Data,Value)
AAA,0
BBB,1
CCC,3
DDD,4
FFF,0
GGG,3
postList: (Data,Value)
AAA,0
BBB,2
DDD,4
EEE,9
FFF,3
Think of PRE as the original list, and POST as the list after some changes done. I would like to compare the two, and categorize them into three categories:
Added Items - An item with a new 'Data' added to the list.
Removed Items - An item was removed from the list.
Diff Items - 'Data' is found in both PRE and POST lists, but their corresponding 'Value' is different.
So when categorized they should look like this:
Added Items:
EEE,9
Removed Items:
CCC,3
GGG,3
Diff Items:
BBB
FFF
I have another DiffItem class, to objects of which I would like to put the final results. DiffItem looks like this:
public class DiffItem
{
public DiffItem() { }
public DiffItem(string data, string type, string pre, string post) { Data = data; DiffType = type; PreVal = pre; PostVal = post; }
public string Data { get; set; }
public string DiffType { get; set; } // DiffType = Add/Remove/Diff
public string PreVal { get; set; } // preList value corresponding to Data item
public string PostVal { get; set; } // postList value corresponding to Data item
}
To accomplish this, first I extended IEqualityComparer and wrote a couple of comparers:
public class DataItemComparer : IEqualityComparer<DataItem>
{
public bool Equals(DataItem x, DataItem y)
{
return (string.Equals(x.Data, y.Data) && string.Equals(x.Value, y.Value));
}
public int GetHashCode(DataItem obj)
{
return obj.Data.GetHashCode();
}
}
public class DataItemDataComparer : IEqualityComparer<DataItem>
{
public bool Equals(DataItem x, DataItem y)
{
return string.Equals(x.Data, y.Data);
}
public int GetHashCode(DataItem obj)
{
return obj.Data.GetHashCode();
}
}
Then used Except() and Intersect() methods as follows:
static void DoDiff()
{
diffList = new List<DiffItem>();
IEnumerable<DataItem> preOnly = preList.Except(postList, new DataItemComparer());
IEnumerable<DataItem> postOnly = postList.Except(preList, new DataItemComparer());
IEnumerable<DataItem> common = postList.Intersect(preList, new DataItemComparer());
IEnumerable<DataItem> added = postOnly.Except(preOnly, new DataItemDataComparer());
IEnumerable<DataItem> removed = preOnly.Except(postOnly, new DataItemDataComparer());
IEnumerable<DataItem> diffPre = preOnly.Intersect(postOnly, new DataItemDataComparer());
IEnumerable<DataItem> diffPost = postOnly.Intersect(preOnly, new DataItemDataComparer());
foreach (DataItem add in added)
{
diffList.Add(new DiffItem(add.Data, "Add", null, add.Value));
}
foreach (DataItem rem in removed)
{
diffList.Add(new DiffItem(rem.Data, "Remove", rem.Value, null));
}
foreach (DataItem pre in diffPre)
{
DataItem post = diffPost.First(x => x.Data == pre.Data);
diffList.Add(new DiffItem(pre.Data, "Diff", pre.Value, post.Value));
}
}
This does work and gets the job done. But I'm wondering if there's a 'better' way to do this. Note that I put quotes around the word 'better', because I don't have a proper definition for what would make this better. Perhaps is there a way to get this done without as many 'foreach' loops and use of Except() and Intersetc(), since I would imagine that behind the Linq there's quite a bit of iterations going on.
Simply put, is there a cleaner code that I can write for this? I'm asking mostly out of academic interest and to expand my knowledge.
I don't think you need your IEqualityComparer:
var added = from a in postList
where !preList.Any(b => b.Data == a.Data)
select new DiffItem(a.Data, "Add", null, a.Value);
var removed = from b in preList
where !postList.Any(a => a.Data == b.Data)
select new DiffItem(b.Data, "Remove", b.Value, null);
var diff = from b in preList
join a in postList on b.Data equals a.Data
where b.Value != a.Value
select new DiffItem(b.Data, "Diff", b.Data, a.Data);
var diffList = added.ToList();
diffList.AddRange(removed);
diffList.AddRange(diff);

Right type when returning anonymous type

I have letter and user tables in database:
User("Id", "Name")
Letter("Id", "UserId", "Title")
and i use this code in class for get letter list:
public static mytype GetList()
{
var lst = (from l in Letters.ToList()
select new {l.Id, l.Title, l.tblUsers.Name}).ToList();
return lst;
}
please help me for choosing the right type. i want not use this code:
public static List<Letter> GetList()
{
List<Letter> lst = new List<Letter>();
lst = (from l in Letters.ToList()
select l).ToList();
return lst;
}
You need to define a type for this.
new {l.Id, l.Title, l.tblUsers.Name}
is the definition of an anonymous class. To use it as a return value, you should define a struct or class which represents the information you want to return. You can use dynamic, but it will easily lead to runtime errors when you change the returned data structure as the callers of the method will not know how the return value looks like.
For example:
struct UserLetter {
public Guid Id {get;set;}
public string Title {get;set;}
public string AuthorName {get;set;}
}
public static IList<UserLetter> GetList()
{
return (from l in Letters
select new UserLetter
{ Id = l.Id, Title = l.Title, AuthorName = l.tblUsers.Name}).ToList();
}
Try like this
class mytype
{
public int id;
public string title;
public string name;
}
public static List<mytype> GetList()
{
return (from l in Letters.ToList() select new mytype{id=l.Id,title=l.Title, name=l.tblUsers.Name}).ToList();
}
You need to apply a join with user table.
public static List<objLetter> GetList()
{
List<objLetter> lst = new List<objLetter>();
lst = from ltr in Letters
join user in Users on ltr.UserId equals user.UserId
select new objLetter {Id = ltr.Id , Title = ltr.Title, Name = user.Name })
return lst;
}
You're creating an anonymous type so either you can create a new class holding the properties you're interested in or use dynamic objects
public static IEnumerable<dynamic> GetList()
{
var lst = (from l in Letters.ToList()
select new {Id = l.Id, Title = l.Title, UserName = l.tblUsers.Name}).ToList();
return lst;
}
Then in your calling code just iterate over the dynamics objects and call the dynamic properties
foreach (var dynamicObject in GetList())
{
Console.WriteLine(dynamicObject.UserName);
}
Unless your dynamic objects have a very small scope in your application, a new class would probably be a better choice since you'll benefit from type-checks

Passing object of anonymous type as parameter to a method

I need do something like this:
public class carros
{
public int id { get; set; }
public string nome { get; set; }
}
public void listar_carros()
{
List<carros> cars = new List<carros>();
cars.Add(new carros{ id= 1, nome = "Fusca" });
cars.Add(new carros{ id= 2, nome = "Gol" });
cars.Add(new carros{ id= 3, nome = "Fiesta" });
var queryResult = from q in cars
where q.nome.ToLower().Contains("eco")
orderby q.nome
select new { q.nome, q.id };
doSomething(queryResult)
}
I need to pass the queryResult variable to function doSomething(). I tried use a dynamic type, List<T> object, but nothing works
public void doSomething(???? queryResult)
{
foreach (carros ca in queryResult)
{
Response.Write(ca.nome);
Response.Write(" - ");
Response.Write(ca.id);
}
}
In general, it's almost always a bad idea to pass anonymous types between methods.
You should make a custom type to hold the nome and id values, then construct it instead of an anonymous type.
In your case, you already have a class that would work: carros. You can just implement your query to create it instead:
var queryResult = from q in cars
where q.nome.ToLower().Contains("eco")
orderby q.nome
select new carros {q.nome, q.id};
Your method would then be:
public void doSomething(IEnumerable<carros> queryResults)
Just wanted to chime in regarding passing anonymous types, while it's been mentioned that its bad juju to pass anonmyous types, you can... if you really wanted to (leveraging dynamic)
public void Anon()
{
var x = new {foo = "bar"};
AnonReciever(x);
}
public static void AnonReciever(dynamic o)
{
Console.WriteLine(o.foo);
}
And this prints bar no problem.
I don't recommend it though. Best to use a custom typed object, which you already have.
Why not declare the new object as type carros?
var qry = from q in Lcars
where q.nome.ToLower().Contains("eco")
orderby q.nome
select new carros {q.nome, q.id};
Your parameter would then:
IEnumerable{carros}
You cannot pass anonymous types* outside the scope of the current method. Use your carros type:
public void listar_carros()
{
List<carros> Lcars = new List<carros>();
Lcars.Add(new carros(1, "Fusca"));
Lcars.Add(new carros(2, "Gol"));
Lcars.Add(new carros(3, "Fiesta"));
var qry = from q in Lcars
where q.nome.ToLower().Contains("eco")
orderby q.nome
select q;
doSomething(qry);
}
public void doSomething(IEnumerable<carros> qry)
{
foreach (carros ca in qry)
{
Response.Write(ca.nome);
Response.Write(" - ");
Response.Write(ca.id);
//Response.Write(ca);
Response.Write("<br />");
}
}
* You can pass them only as an object which is mostly useless since you would want to use them in strong-typed way.

Select template

Is it possible to make a template for SELECT in a LINQ query? Right now I have 6 methods that uses the exact same SELECT, i would like to use a template if possible.
This is the code I'm using, when I want to make a change to the select I have to change the same thing at so many places in my code.
result = query.Select(b => new
{
route_id = b.b.route_id,
name = b.b.name,
description = b.b.description,
distance = b.b.distance,
distance_to_route = (int)b.distance_to_from_me,
departure_place = b.b.departure_place,
arrival_place = b.b.arrival_place,
owner = b.b.user.username,
average_rating = b.avg_rating,
is_favorite = b.is_favorite,
date = b.b.date,
attributes = b.b.route_attributes.Select(c =>
c.route_attribute_types.attribute_name),
coordinates = b.b.coordinates.Select(c =>
new coordinateToSend { sequence = c.sequence,
lat = c.position.Latitude,
lon = c.position.Longitude })
});
Here is a simple example of one way you could do this:
In your example, you're converting the source type to an anonymous type. You could create a class to represent your converted/result type, for example:
public class ResultClass
{
public string ResultPropA { get; set; }
}
For examples sake, lets say the following was the definition of your source class:
public class SourceClass
{
public string SourcePropA { get; set; }
}
Now that you have type definitions for your source and result objects, you can create an extension method to convert a collection of your source class to a collection of your result class:
public static class SourceToResultRepository
{
public static IEnumerable<ResultClass> ConvertSourceToResult
(this IEnumerable<SourceClass> source)
{
return source.Select(s => new ResultClass
{
ResultPropA = s.SourcePropA
//Add all other property transformations here
});
}
}
And here is an example of how you could use it wherever you need to perform the transformation:
//Extension usage:
var result = Database.Source.ConvertSourceToResult();
//Direct usage:
var result = SourceToResultRepository.ConvertSourceToResult(Database.Source);

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