I have created an a list using linq. Unfortunately i want to have it as a property of a class. How can i convert it to a accessable property of a class?
public class Component {
// Property of class Component
public string Komponentenart { get; set;}
public int KomponentenID { get; set;}
public string KomponentenArtikelnummer { get; set;}
public var Variablen { get; set; }
}
public Component(string _filename)
{
string componentFile = _filename;
try
{
StreamReader reader = new StreamReader(componentFile, Encoding.UTF8);
XDocument xmlDoc = XDocument.Load(reader);
var variablen = (from element in xmlDoc.Descendants("variable")
select new
{
Variable = (string)element.Attribute("ID"),
Index = (string)element.Attribute("index"),
Name = (string)element.Attribute("name"),
Path = (string)element.Attribute("path"),
Interval = (string)element.Attribute("interval"),
ConnectorId = (string)element.Attribute("connectorId"),
Type = (string)element.Attribute("type"),
Factor = (string)element.Attribute("factor"),
MaxValue = (string)element.Attribute("maxvalue")
}
).ToList();
}
You can not return instances of anonymous types as return value of functions or properties (From my latest information. A quick google search yielded no indication that that's changed so far). Which means you can't make a list of an anonymous type like you are creating with new {VariableName1 = "123", VarName2 = "456"}.
You could define a class or struct which has the members you need, such as Variable, Index, Name, Path. Then when you build your list, instead of creating an oject with new {...}, you create one of a named type, i.e.:
Define this somewhere:
class MyBunchOfVariables
{
public string Variable ;
public string Index ;
public string Name ;
public string Path ;
public string Interval ;
public string ConnectorId ;
public string Type ;
public string Factor ;
public string MaxValue ;
}
Modify the property type accordingly:
public class Component
{
// Property of class Component
public string Komponentenart { get; set;}
public int KomponentenID { get; set;}
public string KomponentenArtikelnummer { get; set;}
public MyBunchOfVariables Variablen { get; set}; // ### CHANGED TYPE ###
}
And then:
var variablen = (from element in xmlDoc.Descendants("variable")
select
new MyBunchOfVariables
{
Variable = (string)element.Attribute("ID"),
Index = (string)element.Attribute("index"),
Name = (string)element.Attribute("name"),
Path = (string)element.Attribute("path"),
Interval = (string)element.Attribute("interval"),
ConnectorId = (string)element.Attribute("connectorId"),
Type = (string)element.Attribute("type"),
Factor = (string)element.Attribute("factor"),
MaxValue = (string)element.Attribute("maxvalue")
}
).ToList();
Related
I have an entity called User in my EF Model:
public class User
{
public int UserId { get; set; }
public Branch HomeLocation{ get; set; }
public string CellPhone { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserCode { get; set; }
}
Branch is another entity in the model:
public class Branch
{
public int BranchId { get; set; }
public string BranchName{ get; set; }
public string Address { get; set; }
}
My requirement is to get a users list and display it on a grid, and then sort the list by some of the columns (one at a time). Say, for example, sort by username, firstname, lastname and HomeLocation. When sorting by homelocation, it should be sorted by the branch name.
I have many grids like this displaying other data as well. So I want to develop a generic sort mechanism and I have achieved it using some of the examples found in Google, for example this one:
public class GenericSorter<T>
{
public IEnumerable<T> Sort(IEnumerable<T> source, string sortBy, string sortDirection)
{
var param = Expression.Parameter(typeof(T), "item");
var sortExpression = Expression.Lambda<Func<T, object>>
(Expression.Convert(Expression.Property(param, sortBy), typeof(object)), param);
switch (sortDirection.ToLower())
{
case "asc":
return source.AsQueryable<T>().OrderBy<T, object>(sortExpression);
default:
return source.AsQueryable<T>().OrderByDescending<T, object>(sortExpression);
}
}
}
However, sorting by home location fails because it needs to be sorted by an inner property of the user entity. I've tried using Dynamic LINQ library too, but there's no luck.
Update: Note that I have to sort a List, not IQueryable, because my list contains fields encrypted with AE, which don't support DB-level sorting.
Can someone point out to me how to achieve the dynamic sorting from an inner property?
Update2: I followed the example and implemented the sort using the extension methods and this is how it's applied on my list:
var users = (from u in context.Users.Include("Branch")
where (u.FkBranchId == branchId || branchId == -1) && u.IsActive
&& (searchTerm == string.Empty || (u.FirstName.Contains(searchTerm) || u.LastName.Equals(searchTerm)
|| u.UserName.Contains(searchTerm) || u.UserCode.Contains(searchTerm)))
select u).ToList();
var rowCount = users.Count;
var orderedList = users.OrderBy(sortInfo.SortColumn).Skip(pageInfo.Skip).Take(pageInfo.PageSize).ToList();
But I get the following error:
Object of type 'System.Linq.Expressions.Expression1[System.Func2[ClientData.User,System.String]]' cannot be converted to type 'System.Func`2[ClientData.User,System.String]'.
Error is thrown from the following:
object result = typeof(Enumerable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
After this, I'm receiving the following error, in some occasions as explained in the comment:
Adapt the code from #MarcGravell found here.
public static class EnumerableExtensions
{
public static IOrderedEnumerable<T> OrderBy<T>(
this IEnumerable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedEnumerable<T> OrderByDescending<T>(
this IEnumerable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedEnumerable<T> ThenBy<T>(
this IOrderedEnumerable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedEnumerable<T> ThenByDescending<T>(
this IOrderedEnumerable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedEnumerable<T> ApplyOrder<T>(
IEnumerable<T> source,
string property,
string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Enumerable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda.Compile() });
return (IOrderedEnumerable<T>)result;
}
}
UPDATED
Use it from a List<> :
var list = new List<MyModel>();
list = list.OrderBy("MyProperty");
I need to implement filter function with expression parameter.
So i can't apply filtered query to entity.
Entity :
[XmlRoot(ElementName = "Zip")]
public class Zip
{
[XmlAttribute(AttributeName = "code")]
public string Code { get; set; }
}
[XmlRoot(ElementName = "District")]
public class District
{
[XmlElement(ElementName = "Zip")]
public List<Zip> Zip { get; set; }
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
}
[XmlRoot(ElementName = "City")]
public class City
{
[XmlElement(ElementName = "District")]
public List<District> District { get; set; }
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "code")]
public string Code { get; set; }
}
[XmlRoot(ElementName = "AddressInfo")]
public class AddressInfo
{
[XmlElement(ElementName = "City")]
public List<City> City { get; set; }
}
Test case filtered by City name "Berlin". How can apply predicate with function.
public IConverter<T> Filter(Expression<Func<T, bool>> predicate)
{
// ???
return this;
}
I presume you need to filter a collection with a given predicate.
You can define a Filter extension method that takes a predicate as an argument (or simply rely on the already existing collection.Where extension method)
public static class Extensions
{
public static IEnumerable<T> Filter<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
{
return collection.Where(predicate);
}
}
define predicates based on your needs
// Filter by city Berlin
Func<City, bool> berlin = city => city.Name == "Berlin";
// Filter by district Spandau
Func<City, bool> spandau = city => city.Districts.Any(d => d.Name == "Spandau");
// Filter by zip 10115
Func<City, bool> zipcode = city =>
{
var predicate = from district in city.Districts
from zip in district.Zips
where zip.Code == "10115"
select zip;
return predicate.Any();
};
filter the data based on given predicate
var query = from address in addresses
from city in address.Cities.Filter(berlin)
select city;
I have been trying to use to the bulk insert function but every time I use it is showing some mapping error . Has the bulk insert function declaration have changed from nest 1.x to nest 5.x because in 5.x nest documentation I did not find the .bulk() function . Please Suggest
Code for bulk insert:
public void bulkInsert(List<BaseData> recordList, List<String> listOfIndexName)
{
BulkDescriptor descriptor = new BulkDescriptor();
descriptor.Index<BaseData>(op => op
.Document(recordList[j])
.Index(listOfIndexName[j])
);
}
var result = clientConnection.Bulk(descriptor);
}
My list of data that I am passing looks something like this :
[ElasticsearchType(IdProperty = "number")]
class TicketData : BaseData
{
//[ElasticProperty(Index = FieldIndexOption.NotAnalyzed, Store = true)]
[Date(Name = "sys_updated_on", Store = true)]
public DateTimeOffset sys_updated_on { get; set; }
[Text(Name = "number", Store = true)]
public override string number { get; set; }
[Text(Name = "incident_state", Store = true)]
public string incident_state { get; set; }
[Text(Name = "location", Store = true)]
public string location { get; set; }
[Text(Name = "assigned_to", Store = true)]
public string assigned_to { get; set; }
[Text(Name = "u_knowledge_id", Store = true)]
public string u_knowledge_id { get; set; }
[Text(Name = "u_knowledge_id.u_process_role", Store = true)]
public string u_knowledge_id_u_process_role { get; set; }
}
It seems that NEST cannot infer the correct type of your entity because you specify generic type BaseData whereas the actual type is TicketData. You should specify the actual type of entity you want to index. Since you may have different types inside your list, you can get the actual type using GetType() method:
descriptor.Index<BaseData>(op => op
.Document(recordList[j])
.Index(listOfIndexName[j])
.Type(recordList[j].GetType())
);
Currently your query tries to dynamically create a different type with default mapping instead of interpreting it as existing type with explicit mapping
I have one list populated from Database with properties code_type , description , min_value, max_value, id etc
I want to create another lists from list 1 with filter condition value of code_type with only three properties
i.e description , min_value, & max value (code_type is not required). This revised list will be used for to bind View in MVC
\Kindly help for the same
Below is my code for the same. If code ="04" Then populate list for caste & so on. Can I Use Linq for the same?
public class MyPrefernce
{
public string memberid { get; set; }
public string code { get; set; }
public string description { get; set; }
public long? min_value { get; set; }
public long? max_value { get; set; }
public long? sysid { get; set; }
public string isChecked { get; set; }
public List<Caste> lcaste;
public List<MyPrefernce> getPrefence(long sysmemberid, string memberid)
{
List<MyPrefernce> lstObj = new List<MyPrefernce>();
string strQuery = "proc_Get_Member_Preference";
Connection cobj = new Connection();
string strConnection = cobj.getConnectionString();
SqlConnection con = new SqlConnection(strConnection);
con.Open();
SqlCommand cmd = new SqlCommand(strQuery, con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#nSysMemberId", sysmemberid);
SqlDataAdapter ada = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
ada.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
MyPrefernce obj = new MyPrefernce();
obj.code = ds.Tables[0].Rows[i]["code"].ToString();
obj.isChecked = ds.Tables[0].Rows[i]["isChecked"].ToString();
obj.min_value = Convert.ToInt64(ds.Tables[0].Rows[i]["min_value"]);
obj.max_value = Convert.ToInt64(ds.Tables[0].Rows[i]["max_value"]);
obj.sysid = sysid;
obj.memberid = memberid;
lstObj.Add(obj);
}
}
return lstObj;
}
}
public class Caste
{
public int sysId { get; set; }
public string decription { get; set; }
public string? isChecked { get; set; }
}
You should create a new class, defining the fields you need, and use auto-mapper to map the the fields between classes.
I have a custom attribute called FileLink that uses DisplayForModel() to generate an ActionLink to a controller with an ID value.
The attribute looks like this:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idName;
}
}
Is it used in a viewmodel, like so:
public class MyViewModel
{
[HiddenInput(DisplayValue = false)]
public int? Id { get; set; }
[HiddenInput(DisplayValue = false)]
public int? TargetId { get; set; }
[FileLink("SomeAction", "SomeController", "TargetId")]
public string Name { get; set; }
}
I have a custom MetadataProvider derived from DataAnnotationsModelMetadataProvider that puts the attribute values into the metadata AdditionalValues as so:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
The goal is to have DisplayForModel call the DisplayTemplate below to generate a link with the value in TargetId from MyViewModel. So if TargetId is 5, the link will be "SomeController/SomeAction/5"
// This DisplayTemplate for use with the "FileLinkAttribute"
//
// Usage: [FileLinkAttribute("ActionName","ControllerName","IdPropertyName")]
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = *<GET VALUE OF CONTAINER MODEL IdPropertyName>*;
#Html.ActionLink((string)ViewData.Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
With all this in place, I am unable to access the containing object to pull the property value from TargetId. I have tried to do this within the Attribute, within the Provider, and within the DisplayTemplate, with no luck.
Is there a way or place I can access this value to accomplish my intent to read a property value from the viewmodel object containing the attribute?
After reading this post describing the purpose of modelAccessor in a custom DataAnnotationsModelMetadataProvider:
What is the "Func<object> modelAccessor" parameter for in MVC's DataAnnotationsModelMetadataProvider?
I was able to piece together this (very hackish) solution implemented in the custom provider:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
// modelAccessor contains a pointer the container, but the type is not correct but contains the name of the correct type
if (modelAccessor.Target.GetType().ToString().Contains("System.Web.Mvc.AssociatedMetadataProvider"))
{
// get the container model for this metadata
FieldInfo containerInfo = modelAccessor.Target.GetType().GetField("container");
var containerObject = containerInfo.GetValue(modelAccessor.Target);
// get the value of the requested property
PropertyInfo pi = containerObject.GetType().GetProperty(fileLinkAttribute.IdPropertyName);
string idPropertyValue = pi.GetValue(containerObject, null).ToString();
fileLinkAttribute.IdPropertyValue = idPropertyValue;
}
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
I am not sure how to derefence a Func to get it's actual target, and the type name comes out all munged wierdly in this example, such as
"System.Web.Mvc.AssociatedMetadataProvider+<>c__DisplayClassb"
So I convert to a string to check if it contains "System.Web.Mvc.AssociatedMetadataProvider". Probably not the best thing but this is the only way I could get it to work.
Oh, I also added a 4th property to the attribute to contain the value:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public string IdPropertyValue { get; set; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idPropertyName;
}
}
and in the DisplayTemplate I do:
var modelId = fileLinkAttribute.IdPropertyValue;
This should be an editor template for strsing or object as that'swhat you are applying the attribute on. So inside ~/Views/Shared/EditorTemplates/string.cshtml:
#model string
#{
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = fileLinkAttribute.IdPropertyName;
}
#Html.ActionLink(Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
and in your main view:
#Html.EditorFor(x => x.Name)