Populate dropdownlist with a class - class

I want to create a "package program" for address part of my projects. I need it in almost every project so i wanted to make it easier.
So i decided to create a class to load city names to a dropdownlist. Here i coded:
public class Address
{
string connStr = "Data Source...";
public int id { get; set; }
public string name { get; set; }
public Address(int ID, string Name)
{
this.id = ID;
this.name = Name;
}
public List<Address> LoadCities()
{
List<Address> cities = new List<Address>();
SqlConnection con = new SqlConnection(connStr);
SqlCommand cmd = new SqlCommand("select x,y from ...", con);
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Address city = new Address(rdr.GetInt32(0), rdr.GetString(1));
cities.Add(city);
}
con.Close();
return cities;
}
}
This is my package program. I added this as a reference to my project. And tried to populate my dropdownlist as follows:
List<Address> cities = ???
ddlCity.DataTextField = "x";
ddlCity.DataValueField = "y";
ddlCity.DataSource = cities;
ddlCity.DataBind();
At ??? position i just wanted to code like this: List cities = Address.Loadcities();
So, i have a mistake here and i couldnt get it. Because i am new at "class" works.
Thanks in advance.

public static List<Address> LoadCities()
You need the function on that class to be static.
Then you just do:
List<Address> cities = Address.LoadCities();
Here's some documentation for those times when you can't sleep:
http://msdn.microsoft.com/en-us/library/98f28cdx.aspx

Related

Building GroupBy Expression Tree - IEnumerable parameter not defined error

I want to build an expression for IQueryable GroupBy. While at the moment I'm just simplifying the problem to try and get it working, the eventual final implementation will involve the creation of quite complex expression trees so I want to build a complete expression that can then be integrated into other expressions.
I specifically want to build an expression of this overload:
public static System.Linq.IQueryable<TResult> GroupBy<TSource,TKey,TResult> (
this System.Linq.IQueryable<TSource> source,
System.Linq.Expressions.Expression<Func<TSource,TKey>> keySelector,
System.Linq.Expressions.Expression<Func<TKey,System.Collections.Generic.IEnumerable<TSource>,TResult>> resultSelector);
... my problem is in the implementation of the resultSelector and and the IEnumerable<TSource>.
I have a table of Customers (just dummy data for the purposes of working out this problem). This is stored in an SQL DB and I specifically want to use IQueryable to access the data.
public class Customer
{
public int Id { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public int Age { get; set; }
}
I also have a GroupResult class used to hold the results of the GroupBy (I have different constructors which I've been using in my testing to work out where my problem is occurring)
internal class GroupResult
{
public string? Name { get; set; }
public int NumRecords { get; set; }
public decimal AverageAge { get; set; }
public int TotalAge { get; set; }
public GroupResult() { }
public GroupResult(string name)
{
Name = name;
}
public GroupResult(IEnumerable<Customer> customers)
{
Name = Guid.NewGuid().ToString();
NumRecords = customers.Count();
}
public GroupResult(string name, IEnumerable<Customer> customers)
{
Name = name;
NumRecords = customers.Count();
}
}
The main static class that displays prompts to select column to group on, creates the relevant expression tree and executes it
internal static class SimpleGroupByCustomer
{
internal static DataContext db;
internal static void Execute()
{
using (db = new DataContext())
{
//get input
Console.WriteLine();
Console.WriteLine("Simple Customer GroupBy");
Console.WriteLine("=======================");
Console.WriteLine("Simple GroupBy on the Customer Table");
Console.WriteLine();
Console.WriteLine("Select the property that you want to group by.");
Console.WriteLine();
var dbSet = db.Set<Customer>();
var query = dbSet.AsQueryable();
//for this example we're just prompting for a column in the customer table
//GetColumnName is a helper function that lists the available columns and allows
//one to be selected
string colName = Wrapper.GetColumnName("Customer");
MethodInfo? method = typeof(SimpleGroupByCustomer).GetMethod("GetGroupBy",
BindingFlags.Static | BindingFlags.NonPublic);
if (method != null)
{
method = method.MakeGenericMethod(new Type[] { typeof(String), query.ElementType });
method.Invoke(null, new object[] { query, colName });
}
}
}
internal static void GetGroupBy<T, TTable>(IQueryable query, string colName)
{
Type TTmp = typeof(TTable);
var param = Expression.Parameter(TTmp, "c");
var prop = Expression.PropertyOrField(param, colName);
LambdaExpression keySelector = Expression.Lambda<Func<TTable, T>>(prop, param);
var param1 = Expression.Parameter(typeof(T), "Key");
var param2 = Expression.Parameter(typeof(IEnumerable<TTable>), "Customers");
var ci = typeof(GroupResult).GetConstructor(new[] { typeof(T), typeof(IEnumerable<TTable>) });
//var ci = typeof(GroupResult).GetConstructor(new[] { typeof(T) });
//var ci = typeof(GroupResult).GetConstructor(new[] { typeof(IEnumerable<TTable>) });
if (ci == null)
return;
var pExp = new ParameterExpression[] { param1, param2 };
var methodExpression = Expression.Lambda<Func<T, IEnumerable<TTable>, GroupResult>>(
Expression.New(ci, new Expression[] { param1, param2 }), //<--- ERROR HERE
pExp
);
Type[] typeArgs = new Type[] { typeof(TTable), typeof(T), typeof(GroupResult) };
Expression[] methodParams = new Expression[] { query.Expression, keySelector, methodExpression };
var resultExpression = Expression.Call(typeof(Queryable), "GroupBy", typeArgs, methodParams);
IQueryable dbQuery = query.Provider.CreateQuery(resultExpression);
if (dbQuery is IQueryable<GroupResult> results)
{
foreach (var result in results)
{
Console.WriteLine("{0,-15}\t{1}", result.Name, result.NumRecords.ToString());
}
}
}
}
When I run this and try and iterate through the results I get the following exception:
System.InvalidOperationException: 'variable 'Customers' of type 'System.Collections.Generic.IEnumerable`1[ExpressionTrees3.Data.Customer]' referenced from scope '', but it is not defined'
which is being caused by the param2 ParameterExpression marked above.
If I use the GroupResult constructor that just takes the key value
var ci = typeof(GroupResult).GetConstructor(new[] { typeof(T) });
and omit the param2 from the Lambda body definition the code works as expected and I get a collection of GroupResult records containing the distinct key values in the Name field (but obviously no summary value).
I've tried everything I can think of and just can't get past this error - it's as though the GroupBy is not actually producing the IEnumerable grouping of Customers for each key.
I suspect I'm missing something really obvious here, but just can't see it. Any help would really very much appreciated.
Please note that I am after answers to this specific issue, I'm not looking for alternative ways of doing a GroupBy (unless there's a fundamental reason why this shouldn't work) - this will be rolled into a much larger solution for building queries and I want to use the same process throughout.
Thanks Svyatoslav - as I thought, it was me being especially dumb!
Your comments, as well as a discussion with a friend who has a lot SQL knowledge pointed me in the right direction.
I had been thinking that the GroupBy expression was going to return an Enumerable for each key value and was trying to pass that into a function ... it always felt wrong, but I just ignored that and kept going.
It's obvious now that I need to tell the GroupBy what to calculate and return (i.e. your comment about aggregation).
So for this easy example, the solution is very simple:
var pExp = new ParameterExpression[] { param1, param2 };
var countTypes = new Type[] { typeof(TTable) };
var countParams = new Expression[] { param2 };
var countExp = Expression.Call(typeof(Enumerable), "Count", countTypes, countParams);
var methodExpression = Expression.Lambda<Func<T, IEnumerable<TTable>, GroupResult>>(
Expression.New(ci, new Expression[] { param1, countExp }),
pExp
);
Just by adding the 'Count' expression into the GroupBy method call it works!
.. and adding a new ctor for GroupResult:
public GroupResult(string name, int count)
{
Name = name;
NumRecords = count;
}
(yep, I feel a bit stupid!)

Entity Framework piece together LINQ to Entity Queries

I need some help here. I am trying to make a portion of an EF Query reusable.
var query = from sr in SomeEFRepository.SelectAll()
select new {
KeyValuePivotField1 = (from kvd in sr.KeyValueData
where kvd.KeyName == "FieldName1"
select kvd.Value).FirstOrDefault(),
KeyValuePivotField2 = (from kvd in sr.KeyValueData
where kvd.KeyName == "FieldName2"
select kvd.Value).FirstOrDefault(),
KeyValuePivotField3 = (from kvd in sr.KeyValueData
where kvd.KeyName == "FieldName3"
select kvd.Value).FirstOrDefault()
}
If you look you can see that I am constantly repeating myself with the following code.
(from kvd in sr.KeyValueData
where kvd.KeyName == "SomeFieldName"
select kvd.Value).FirstOrDefault(),
How can I make a method that EF will recognize in order to do something like this?
var query = from sr in SomeEFRepository.SelectAll()
select new {
KeyValuePivotField1 = GetFieldFromKeyValue("FieldName1"),
KeyValuePivotField2 = GetFieldFromKeyValue("FieldName2"),
KeyValuePivotField3 = GetFieldFromKeyValue("FieldName3"),
}
Any suggestions will help. I have been reading about Expression Trees but not sure if
that would be a good approach or even possible.
Note: I am using EF 5.0 with DBContext.
Extension methods seem like a good fit for this. I don't know exactly what you are doing so this is a example
Customer class
public class Customer{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return string.Format("Customer is {0} {1}", this.FirstName, this.LastName);
}
}
CustomerExtensionMethod
//Class MUST be static
public static class CustomerExtensionMethods
{
//Method MUST be static and use this keyword to be an extension method
public static Customer GetByFirstName(this IEnumerable<Customer> source, string value)
{
return source.Where(c => c.FirstName == value).FirstOrDefault();
}
}
Main program to show how it works
var customers = new List<Customer>
{
new Customer { Id = 1, FirstName = "Foo", LastName = "Bar" },
new Customer { Id = 2, FirstName = "Mark", LastName = "Whoknows" },
new Customer { Id = 3, FirstName = "Ronald", LastName = "McDonald" },
};
var userWithFirstNameOfRonald = customers.GetByFirstName("Ronald");
Console.WriteLine(userWithFirstNameOfRonald.ToString());
This should print "Customer Is Ronald McDonald". The important parts are commented. The Class that contains the method should be static and the method needs to be static. Along with that the first parameter of the method needs to be this to signal it is an extension method. This will allow you to call it on the specific type you put for the first parameter.
Found a great answer and article to my troubles.
http://www.codeproject.com/Articles/402594/Black-Art-LINQ-expressions-reuse
A nice NuGet Package LinqExpressionProjection 1.0.0 that is perfect for my problem.
http://nuget.org/packages/LinqExpressionProjection

Automapper and mapping Parent / Child relationships causes a StackOverflow error when Entity Framework generate DynamicProxies?

I have tried many options to get Automapper to correctly map Parent / Child relationships.
Model:
//Entity
public class WorkArea
{
public Guid Id;
public Name {get;set;}
public Guid? ParentWorkAreaId {get;set;} //for entity Framework Foreign Key
public WorkArea ParentWorkArea {get;set;}
public ICollection<WorkArea> ChildWorkareas {get;set;}
}
//DTO
public class WorkAreaDto
{
public Guid Id;
public Name {get;set;}
public Guid? ParentWorkAreaId {get;set;} //for entity Framework Foreign Key
public WorkAreaDto ParentWorkArea {get;set;}
public ICollection<WorkAreaDto> ChildWorkareas {get;set;}
}
This mapping causes a Stack Overflow:
Mapper.CreateMap<WorkArea,WorkAreaDto>();
I tried something exactly like this and had the same error
I then created a custom TypeConverter, but not only do I have to write recursive methods for children, but also parents. Just seems like a lot of work do get this to map correctly. Not sure if I am doing something wrong. I am using 2.0
Update:
I think my issue is the System.Data.Entity.DynamicProxies generated by Entity Framework.
This works perfectly well for me, perhaps you should inspect your data:
[TestMethod]
public void TestMethod1()
{
Mapper.CreateMap<WorkArea, WorkAreaDto>();
var source = CreateSource();
WorkAreaDto destination = new WorkAreaDto();
Mapper.Map(source, destination);
Assert.AreEqual(destination.ChildWorkareas.Count, 3);
}
private WorkArea CreateSource()
{
var id = Guid.NewGuid();
var result = new WorkArea();
result.Id = id;
result.Name = "Name" + id.ToString();
result.ParentWorkArea = CreateSourceParent(result);
result.ParentWorkAreaId = result.ParentWorkArea.Id;
result.ChildWorkareas = CreateSourceChildren(result);
return result;
}
private ICollection<WorkArea> CreateSourceChildren(WorkArea parent)
{
var result = new Collection<WorkArea>
{
new WorkArea() { Id = Guid.NewGuid(), Name = "Child1", ParentWorkArea = parent, ParentWorkAreaId = parent.Id },
new WorkArea() { Id = Guid.NewGuid(), Name = "Child2", ParentWorkArea = parent, ParentWorkAreaId = parent.Id },
new WorkArea() { Id = Guid.NewGuid(), Name = "Child3", ParentWorkArea = parent, ParentWorkAreaId = parent.Id }
};
return result;
}
private WorkArea CreateSourceParent(WorkArea source)
{
var id = Guid.NewGuid();
var result = new WorkArea();
result.Id = id;
result.Name = "Name" + id.ToString();
result.ChildWorkareas = new Collection<WorkArea>
{
source
};
return result;
}

Converting ESQL to LINQ to Entities. Sort by related entities

I am using EF + RIA and unfortunately meet some problems with sorting by related entities.
For such purpose there is ESQL query that I implemented (found only this solution):
var queryESQL = string.Format(
#" select VALUE ent from SomeEntities as ent
join Attributes as ea ON ea.EntityId = ent.Id
where ea.AttributeTypeId = #typeId
order by ea.{0} {1}", columnName, descending ? "desc" : "asc");
var query = ObjectContext.CreateQuery<SomeEntity>(queryESQL, new ObjectParameter("typeId", attributeTypeId));
Tables have following structure:
<Attribute>:
int Id;
decimal DecimalColumn;
string StringColumn;
int EntityId;
int AttributeTypeId;
<SomeEntity>:
int Id;
string Name;
Is there any way to rewrite this stuff(sorting), using LINQ to Entities approach?
Here's my attempt, I can't guarantee it will work. I need to think more on how to get a dynamic column name, I'm not sure on that one. EDIT: you can use a string for the order column.
int typeId = 1115;
bool orderAscending = false;
string columnName = "StringColumn";
var query = from ent in SomeEntities
join ea in Attributes on ea.EntityId = ent.Id
where ea.AttributeTypeId = typeId;
if(orderAscending)
{
query = query.OrderBy(ea => columnName).Select(ea => ea.Value);
}
else
{
query = query.OrderByDescending(ea => columnName).Select(ea => ea.Value);
}
var results = query.ToList(); // call toList or enumerate to execute the query, since LINQ has deferred execution.
EDIT: I think that ordering after the select stops is from ordering by. I moved the select statement to after the order by. I also added the "query =", but I'm not sure if that is needed. I don't have a way to test this at the moment.
EDIT 3: I fired up LINQPad today and made a few tweaks to what I had before. I modeled your data in a Code-first approach to using EF and it should be close to what you have.
This approach works better if you're just trying to get a list of Attributes (which you aren't). To get around that I added an Entity property to the MyAttribute class.
This code works in LINQPAD.
void Main()
{
// add test entities as needed. I'm assuming you have an Attibutes collection on your Entity based on your tables.
List<MyEntity> SomeEntities = new List<MyEntity>();
MyEntity e1 = new MyEntity();
MyAttribute a1 = new MyAttribute(){ StringColumn="One", DecimalColumn=25.6M, Id=1, EntityId=1, AttributeTypeId = 1, Entity=e1 };
e1.Attributes.Add(a1);
e1.Id = 1;
e1.Name= "E1";
SomeEntities.Add(e1);
MyEntity e2 = new MyEntity();
MyAttribute a2 = new MyAttribute(){ StringColumn="Two", DecimalColumn=198.7M, Id=2, EntityId=2, AttributeTypeId = 1, Entity=e2 };
e2.Attributes.Add(a2);
e2.Id = 2;
e2.Name = "E2";
SomeEntities.Add(e2);
MyEntity e3 = new MyEntity();
MyAttribute a3 = new MyAttribute(){ StringColumn="Three", DecimalColumn=65.9M, Id=3, EntityId=3, AttributeTypeId = 1, Entity=e3 };
e3.Attributes.Add(a3);
e3.Id = 3;
e3.Name = "E3";
SomeEntities.Add(e3);
List<MyAttribute> attributes = new List<MyAttribute>();
attributes.Add(a1);
attributes.Add(a2);
attributes.Add(a3);
int typeId = 1;
bool orderAscending = true;
string columnName = "StringColumn";
var query = (from ent in SomeEntities
where ent.Attributes.Any(a => a.AttributeTypeId == typeId)
select ent.Attributes).SelectMany(a => a).AsQueryable();
query.Dump("Pre Ordering");
if(orderAscending)
{
// query = is needed
query = query.OrderBy(att => MyEntity.GetPropertyValue(att, columnName));
}
else
{
query = query.OrderByDescending(att => MyEntity.GetPropertyValue(att, columnName));
}
// returns a list of MyAttributes. If you need to get a list of attributes, add a MyEntity property to the MyAttribute class and populate it
var results = query.Select(att => att.Entity).ToList().Dump();
}
// Define other methods and classes here
}
class MyAttribute
{
public int Id { get; set; }
public decimal DecimalColumn { get; set; }
public string StringColumn { get; set; }
public int EntityId { get; set; }
public int AttributeTypeId { get; set; }
// having this property will require an Include in EF to return it then query, which is less effecient than the original ObjectQuery< for the question
public MyEntity Entity { get; set; }
}
class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<MyAttribute> Attributes { get; set; }
public MyEntity()
{
this.Attributes = new List<MyAttribute>();
}
// this could have been on any class, I stuck it here for ease of use in LINQPad
// caution reflection may be slow
public static object GetPropertyValue(object obj, string property)
{
// from Kjetil Watnedal on http://stackoverflow.com/questions/41244/dynamic-linq-orderby
System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}

How to populate a DropDownList in ASP.Net MVC2?

I have the following database schema:
Here's how I populate a DropDownList in my AreaController.cs:
public ActionResult Edit(int id)
{
Area area = areaRepository.GetArea(id);
JefeRepository jefe = new JefeRepository();
ViewData["Jefes"] = new SelectList(jefe.FindAllJefes().ToList(), "ID", "Nombre", area.Jefe.Nombre);
return View(area);
}
Then in my View I display it like so:
<%: Html.DropDownList("IDJefe", (SelectList)ViewData["Jefes"]) %>
The DropDownList loads correctly but only shows the Name of the Jefe. I want to display both name and last name. How can I achieve this?
I've tried doing something like this but it only display the first name.
ViewData["Jefes"] = new SelectList(jefe.FindAllJefes().ToList(), "ID", "Nombre", area.Jefe.Nombre + area.Jefe.Apellido);
This is how it shows:
In your class you can make an property which will combine it for you and also can be bind to your list, f.e. if I have Person class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
}
Then you can easily bind it like:
ViewData["Persons"] = new SelectList(persons, "Id", "FullName ", ...);
As far as it have just the getter it will not involved into your business logic processes - it will only helps ;)
PS. Sorry for another example, but I really do not understand spanish ;)