I set an nHibernate restriction for a project Id like so:
var attachmentProperties = new System.Collections.Generic.Dictionary<string, object>();
attachmentProperties.Add("Id", this.project.Id);
so it returns anything with that project Id by setting the Restrictions:
NHibernate.Criterion.Restrictions.AllEq(attachmentProperties));
This works. I now want to add another restriction using the equivalent of a SQL Like. I tried:
attachmentProperties.Add(NHibernate.Criterion.Restrictions.Like("Type", "%dog%"));
There is no argument given that corresponds to required formal
parameter value
I want to get anything in which the Type contains "dog" (in addition to the Id matching). How do I do this?
You have two options:
Have all the Dog classes implement a common interface (IDog). Then, the dictionary will be:
new System.Collections.Generic.Dictionary<string, IDog>();
or, you could do this, which might be a little strange, if what's up top isn't available for some reason where you validate the Add method. You'd similarly have to have checks on other methods.
class DogDictionary : Dictionary<string, object>
{
public virtual void Add(KeyValuePair<string, object> item)
{
if (item.Value.GetType().ToString().ToUpper().Contains("DOG"))
throw new ApplicationException("Invalid Data Type for Value. Should Have 'Dog' in the Object Name");
}
}
I'd go with the first option though.
Another way is to create a Restrictions.Conjunction for the Criteria:
Conjunction conjunction = Restrictions.Conjunction();
conjunction.Add(Restrictions.Eq("Id", this.project.Id));
conjunction.Add(Restrictions.Like("Type", "%dog%"));
conjunction.Add(Restrictions.Not(Restrictions.Like("Type", "%cat%")));
Related
I am trying to build a solution fitting with the problem of not knowing what kind of Setting type I am dealing with.
I got a Dictionary<string, Type> (which I initially wanted to make <string, class> but that didn't work)
that I want to fill with the setting code and the type of class attached to it i.e.
{ "person_customField", typeof(CustomFieldModel) }
Why I want to do this is because I have a field in my database filled with json data that should be deserialized to a List<> but I don't know what kind of setting it is until I get the object from the database. I can use the Code field to detemine what type it is (person_CustomField should use the CustomFieldModel class, but emailSetting should use EmailSettingModel to match parameters to.
Is there a way to successfully make this statement work with?
JsonConvert.DeserializeObject<List<SettingTypes[record.SettingCode]>>(record.SettingValues).ToList<ISetting>()
Or should I go a different route
Code Sample:
public static readonly Dictionary<string, Type> SettingTypes = new Dictionary<string, Type>()
{
{ "person_CustomFields", typeof(CustomFieldModel)},
};
public static TenantSettingEdit ConvertToTenantSettingEdit(this T_TenantSetting rec)
{
var test = SettingTypes[rec.TENS_Code];
TenantSettingEdit item = new TenantSettingEdit()
{
IDToken = rec.TENS_TenantSettingID.toVirtualGuid().ToString(),
Code = rec.TENS_Code,
Settings = JsonConvert.DeserializeObject<List<SettingTypes[rec.TENS_Code]>>(rec.TENS_Setting).ToList<ITenantSetting>(),
IsActive = rec.TENS_ActiveRec,
};
return item;
}
(I have done this before with PHP but I am not sure if this is even remotely possible with C#)
Why I want to do this is because I have a field in my database filled
with json data that should be deserialized to a List<> but I don't
know what kind of setting it is until I get the object from the
database.
If you're using Json.Net for JSON serialization/deserialization you can use the TypeNameHandling property to embed Type information in the resulting JSON. That JSON can the be deserialized by Json.Net without additional information. If it is necessary to map custom values to the types instead of the automatically generated ones you can use a SerializationBinder (check out this answer).
If none of those help you, you can still fall back to reflection in the way M Kloster describes.
You cannot use a variable as the type parameter in the code, no. What you need to do is to generate the type-specific method by reflection:
var genericMethod = ((Func<string, int>)Json.DeserializeObject<int>).Method.GetGenericMethodDefinition();
var boundMethod = genericMethod.MakeGenericMethod(SettingTypes[record.SettingCode]);
var result = boundMethod.Invoke(null, rec.TENS_Setting)...
I'm making a program which when a chemical symbol of an element is entered, it'll return information of that element onto the form. This is simple to do but it want to try and keep my code as efficient as possible.
My dictionary:
Dictionary<string, object> alkaliM = new Dictionary<string, object>();
In my code also:
alkaliM.Add("Li", new AlkaliMetals.Lithium());
elementSymbol is my input string from the textbox
I'm trying to set elementName.Text to the property "name" of my AlkaliMetals.Lithium object. However, i can't simply put:
elementName.Text = alkaliM[elementSymbol.Text]; as i can't set an object as a string. ("Cannot implicty convert type "object" to "string"")
Is there any way to set elementName.Text to AlkaliMetals.Lithium.name using only the key?
I have a separate file that has a main class AlkaliMetals and subclasses for each of the alkali metals like Lithium.
If my description doesn't make sense let me know and i'll try to explain what i mean.
You can make all the sub classes in AlkaliMetals.cs implement an abstract class CommonAbstractClass
having the property name
Define you dictionary as Dictionary<string, CommonAbstractClass>
Then use your dictionary as follows elementName.Text = alkaliM[elementSymbol.Text].name;
You can find the name property (if you are absolutely sure it exists) using dynamic cast:
elementName.Text = (alkaliM[elementSymbol.Text] as dynamic).name
However, a more efficient approach would be Object Oriented Design:
Define a class named ChemicalElement, add name property to it and then derive Lithium from ChemicalElement. This way you can write:
elementName.Text = (alkaliM[elementSymbol.Text] as ChemicalElement).name
Best solution is to define your dictionary like this:
Dictionary<string, ChemicalElement> alkaliM = new Dictionary<string, ChemicalElement>();
And then access the name like:
elementName.Text = alkaliM[elementSymbol.Text].name
If i generate my entities through Entity Framework Database First, and i want to use a function like that:
AuditManager.DefaultConfiguration.Exclude<T>();
considering that the number of times i want to call it should be equal to the number of entities
ex:
AuditManager.DefaultConfiguration.Exclude<Employee>();
AuditManager.DefaultConfiguration.Exclude<Department>();
AuditManager.DefaultConfiguration.Exclude<Room>();
Now how to Loop through selected number of entities and pass every one to the Exclude function ?
The obvious solution would be to call the method for every entity-type you want to hide. Like this:
AuditManager.DefaultConfiguration.Exclude<Employee>();
AuditManager.DefaultConfiguration.Exclude<Department>();
AuditManager.DefaultConfiguration.Exclude<Room>();
You can add conditional statements (ifs) around them to do it dynamically.
Howevery, if you want a fully flexible solution, where you call the Exclude method based on metadata, you need something else. Something like this:
var types = new[] { typeof(Employee), typeof(Department), typeof(Room) };
var instance = AuditManager.DefaultConfiguration;
var openGenericMethod = instance.GetType().GetMethod("Exclude");
foreach (var #type in types)
{
var closedGenericMethod = openGenericMethod.MakeGenericMethod(#type);
closedGenericMethod.Invoke(instance, null);
}
This assumes that the Exclude<T> method is an instance method on whatever instance DefaultConfiguration points to.
An alternative to looping through your entity types is to make the entities you don't want audited implement the same interface and exclude that. For example:
public interface IExcludeFromAudit
{ }
And your entities:
public class Order : IExcludeFromAudit
{
//snip
}
And now just exclude the interface:
AuditManager.DefaultConfiguration.Exclude<IExcludeFromAudit>();
The benefit of this is that it's now easy to control which ones are excluded.
I have the following:
using (var dsProperties = GetDataset(SP_GET_APPLES, arrParams))
{
var apples= dsProperties.Tables[0].AsEnumerable()
.Select(r => new Apple()
{
Color = r[0].ToString(),
Year = r[1].ToString(),
Brand= r[2].ToString()
});
return apples.ToList();
}
Now, I would like to have an extension method on Dataset to which I can pass the needed Type as a parameter and get the intended List back... something like
dsProperties.GetList(Apple);
which can also be used for
using (var dsProperties = GetDataset(SP_GET_ORANGES, arrParams)){
dsProperties.GetList(Orange); }
Is there a way to accomplish this?
How about this?
static IEnumerable<T> GetList<T>(this DataSet dataSet, Func<DataRow, T> mapper) {
return dataSet
.Tables[0]
.AsEnumerable()
.Select(mapper);
}
And usage:
dsProperties.GetList<Apple>(r =>
new Apple {
Color = r[0].ToString(),
Year = r[1].ToString(),
Brand= r[2].ToString()
});
This mapping can well be put in another place as well.
Something like the (untested) following, but it would need a lot of error handling added (if a field is missing, wrong data type, nulls).
public static IEnumerable<T> GetEnumeration<T>(this DataSet dataset) where T: new()
{
return dataset.Tables[0].AsEnumerable()
.Select(r => {
T t = new T();
foreach (var prop in typeof(T).GetProperties())
{
prop.SetValue(t, r[prop.Name]);
}
return t;
});
}
You would use it like dataset.GetEnumeration<Apple>().ToList(). Note that this uses reflection and could be slow for large data sets, and makes a lot of assumptions, such as each field in the type matching the columns in the data table. Personally I use a repository for each business object which explicitly constructs the object from a data row. More work to set up but in the long run I have a bit more control. You could probably look at an ORM framework like NHibernate as well.
I think your best (and cleanest, as in "reflection-less") bet will be to create a constructor for each involved class (Apple, Orange, etc.) that takes a DataRow and initializes the object based on the row. Then, your code simplifies to dsProperties.Tables[0].AsEnumerable().Select(r => new Apple(r)). Simplifying it further into a generic extension method will be difficult because you cannot have type constraints that specify the existence of a constructor that takes certain parameters.
If you really want a generic extension method for this, I think you'll have to use the factory pattern, so that the extension method can instantiate a factory that can convert DataRows into the desired type. That's gonna be quite a bit of code for (I think) quite little benefit, but I can create an example if you'd like to see it.
Edit: I'd advise you to rather create an extension method that lets you do this: dsProperties.CreateFruits(r => new Apple(r)). That's about as short as it would be with the extension method you requested. You'll still have to create the constructors, though, so if what you're really after is to save coding on the object constructions, then you'll probably need reflection-based approaches as described in the other answers.
Edit again: #MikeEast beat me to my last suggestion.
Is there a standard naming convention between your stored procedures and your types? If so then you can reflect on the type and retrieve its name then convert that to its stored procedure.
Otherwise, you could have a static dictionary of the type name as a key and the value being the associated stored procedure. Then in your method you would look up the stored procedure after reflecting on the type.
Also I believe you will need to use generics. Something like (it's been a while since i've done generics):
public static IEnumerable<T> GetList<T>(this DataSet ds)
The conversion of columns to properties on your object would also be achieved through reflection. You would loop over the properties on the object and find a matching column to insert the value.
Hope this helps to get you started.
I like MikeEast's approach, but don't like the idea that you have to pass the mapping to every call to GetList. Try this variation instead:
public static class DataSetEx
{
private static Dictionary<Type, System.Delegate> __maps
= new Dictionary<Type, System.Delegate>();
public static void RegisterMap<T>(this Func<DataRow, T> map)
{
__maps.Add(typeof(T), map);
}
public static IEnumerable<T> GetList<T>(this DataSet dataSet)
{
var map = (Func<DataRow, T>)(__maps[typeof(T)]);
return dataSet.Tables[0].AsEnumerable().Select(map);
}
}
Now, given the classes Apple & Orange call the following methods to register the maps:
DataSetEx.RegisterMap<Apple>(r => new Apple()
{
Color = r[0].ToString(),
Year = r[1].ToString(),
Brand= r[2].ToString(),
});
DataSetEx.RegisterMap<Orange>(r => new Orange()
{
Variety = r[0].ToString(),
Location = r[1].ToString(),
});
Then you can just call GetList without the map like so:
var ds = new DataSet();
// load ds here...
// then
var apples = ds.GetList<Apple>();
// or
var oranges = ds.GetList<Orange>();
That gives some nice code separation without the need for reflection or repetition.
This also doesn't stop you using a hybrid approach of using reflection in cases where a map hasn't explicitly been defined. You kind of can get the best of both worlds.
Consider the following:
// select a subset of the DataTable
var subset = DataTable.Where(...).Select(row => new
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
// or create a new object
var subset = new {
Id = 1,
Name = "something random",
Email = "name#domain.tld"
};
Is there any way to use the subset variable as a parameter to a method, without it being cast as a plain Object? Can you somehow carry the auto-generated type of the variable?
I am trying to avoid having to create new classes every time I want to pass LINQ subsets to methods.
Random generic approaches are welcome.
No, passing anonymous types about isn't generally a good idea because you lose the type information*. You should create a concrete type and use that instead.
var subset = DataTable.Where(...).Select(row => new SomeType
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
Alternatively you can use the Tuple type if you are using .NET 4. This is a simple way to create "disposable" types and still get some type-safety.
*Actually there is a workaround, but I regard it is an ugly hack and would advise that you don't do it.
If I need to do this, I use resharper's "Replace Anonymous Type With Named Class" refactoring option. Then you have an appropriate named type to expose over the API, and you haven't had to do any work. This also gives you options to create it immutable (like anonymous types) or mutable, nested vs top-level, etc.
BTW, I don't recommend struct here (from the question).
Another option is to pass the behaviour into the method - i.e. an Action<int,string,string> callback - then do something like:
foreach(item in query) callback(item);
However, I don't like this as it is not obvious that there is a likely error in:
DoSomething(args, (id, email, name) => Email(To: email, Subject: name));
(the error being that it should probably be (id, name, email), if you see what I mean)
You can use a generic method:
public static void Foo<T>(T item)
{
// Do whatever
}
Then if you call
Foo(subset);
the compiler will infer T for you. Whether or not that actually helps you is another matter... it depends on what the method is meant to do. Obviously Foo can't refer to Id, Name, Email etc.
In general, if multiple methods should know about the same members, then you should use a named type. The usual case for passing them to generic methods is where the method really doesn't care about what type is involved, such as in LINQ.
I've made a feature request for C# 5 that we should be able to create types which have all the same features as anonymous types (immutability, equality, hash code generation, ToString dumping) but for simple named types. We'll see if it actually happens...
Anonymous Types don't provide much help outside of the context they where created.
If you need to pass an Anonymous Type to a method, either this method is very generic like (Example)
void PrintAllObjectProperties(object obj);
witch you would use reflection to do the work, or you are doing something wrong.
Here's what I came up with...
Extension method on Object:
public static class ObjectExtensions
{
/// <summary>
/// Cast Object to anonymous type.
/// E.G.: new Object().ToAnonymousType(new { Property = new Type() });
/// </summary>
public static T ToAnonymousType<T>(this Object o, T t)
{
return (T)o;
}
}
Usage:
public void HandleAnonymousTypeAsParameter(Object o)
{
var anonymousType = o.ToAnonymousType(new
{
Id = new Int32(),
Foo = new String(),
Bar = new String()
});
// ... You can do this in even less characters:
var anonymousType = o.ToAnonymousType(new { Id = 0, Foo = "", Bar = "" });
}
HandleAnonymousTypeAsParameter(new
{
Id = 1,
Foo = "foo",
Bar = "bar"
});
Credits goes to John Skeet and Thomas P.