The following query takes a while to return:
db.Query<Person>(x => x.StartsWith("Chr", StringComparison.CurrentCultureIgnoreCase))
is there a way to get this working correctly? ie faster?
Maybe you ran into a limitation of db4o’s query-optimization. Normally Native Queries and LINQ-Queries are translated into a low level SODA-query. When this optimization fails, db4o instantiates the objects in the database in order to execute the query. As you can imagine this can be quite slow.
The best current solution is to use a SODA directly for this case. For example a class with one property:
public class SimpleObject
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
The native query like this:
var result = db.Query<SimpleObject>(x => x.Name.StartsWith ("Chr",StringComparison.CurrentCultureIgnoreCase));
Can be represented by this SODA-Query:
IQuery query = db.Query();
query.Constrain(typeof (SimpleObject)); // restrict to a certain class
query.Descend("name").Constrain("Chr").StartsWith(false); // the field 'name' starts with 'chr', case-insensitive
foreach (var s in query.Execute())
{
//
}
I hope future versions of the Query-Optimizer support this case directly.
adding and index on the column you're comparing would probably help.
http://developer.db4o.com/Documentation/Reference/db4o-7.4/net35/tutorial/docs/Indexes.html#outline219
Related
I'm trying to use System.Reflections to get a DbSet<T> dynamically from its name.
What I've got right now is:
The DbSet name
The DbSet's Type stored on a variable
The issue I'm facing comes out when trying to use the dbcontext.Set<T>() method, since (these are my tries so far):
When I try to assign to <T> my DbSet Type, it throws me the following compilation error:
"XXX is a variable but is used like a type"
If I try with using both the Extension methods that you will find below in my code (which I made in order to try to get an IQueryable<T>), it returns a IQueryable<object>, which unfortunately is not what I am looking for, since of course when I try to manipulate it with further Reflections, it lacks of all the properties that the original class has…
What am I doing wrong? How can I get a DbSet<T>?
My code is the following, but of course, let me know if you need more infos, clarifications or code snippets.
My Controller's Method:
public bool MyMethod (string t, int id, string jsonupdate)
{
string _tableName = t;
Type _type = TypeFinder.FindType(_tableName); //returns the correct type
//FIRST TRY
//throws error: "_type is a variable but is used like a type"
var tableSet = _context.Set<_type>();
//SECOND TRY
//returns me an IQueryable<object>, I need an IQueryable<MyType>
var tableSet2 = _context.Set(_type);
//THIRD TRY
//always returns me am IQueryable<object>, I need an IQueryable<MyType>
var calcInstance = Activator.CreateInstance(_type);
var _tableSet3 = _context.Set2(calcInstance);
//...
}
Class ContextSetExtension
public static class ContextSetExtension
{
public static IQueryable<object> Set(this DbContext _context, Type t)
{
var res= _context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
return (IQueryable<object>)res;
}
public static IQueryable<T>Set2<T>(this DbContext _context, T t)
{
var typo = t.GetType();
return (IQueryable<T>)_context.GetType().GetMethod("Set").MakeGenericMethod(typo).Invoke(_context, null);
}
}
EDIT Added TypeFinder's inner code.
In brief, this method does the same of Type.GetType, but searches Type on ALL the generated assemblies
public class TypeFinder
{
public TypeFinder()
{
}
public static Type FindType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
var result = (from elem in (from app in assemblies
select (from tip in app.GetTypes()
where tip.Name == name.Trim()
select tip).FirstOrDefault())
where elem != null
select elem).FirstOrDefault();
return result;
}
}
UPDATE as requested in the comments, here's the specific case:
In my DB i've got some tables which are really similar each other, so the idea was to create a dynamic table-update method which would be good for every table, just passing to this method the table name, the ID of the row to update and the JSON containing data to update.
So, in brief, I would perform some updates on the table given in input as DbSet type, updating the row with ID==id in input with the data contained inside the JSON, which will be parsed inside an object of type X(the same of dbset)/into a dictionary.
In pseudo-code:
public bool MyMethod (string t, int id, string jsonupdate)
{
string _tableName = t;
Type _type = TypeFinder.FindType(_tableName); //returns the correct type
//THIS DOESN'T WORKS, of course, since as said above:
//<<throws error: "_type is a variable but is used like a type">>
var tableSet = _context.Set<_type>();
//parsing the JSON
var newObj = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonupdate, _type);
//THIS OF COURSE DOESN'T WORKS TOO
//selecting the row to update:
var toUpdate = tableSet.Where(x => x.Id == id).FirstOrDefault();
if(toUpdate!=null)
{
var newProperties = newObj.GetType().GetProperties();
var toUpdateProperties = toUpdate.GetType().GetProperties();
foreach(var item in properties)
{
var temp = toUpdateProperties.Where(p => p.Name==item.Name)
{
//I write it really in briefand fast, without lots of checks.
//I think this is enough, I hope
temp.SetValue(toUpdate, item.GetValue());
}
}
_context.SaveChanges();
}
return false;
}
returns me an IQueryable<object>, I need an IQueryable<MyType>
Well, that will never work. Your IQueryable cannot be of type IQueryable<MyType>because that would mean the compiler would need to know what MyType is and that is not possible, because the whole point of this exercise is to decide that on runtime.
Maybe it's enough to know that those objects are in fact instances of MyType?
If not, I think you have painted yourself into a corner here and you are trying to figure out what paint to use to get out of there. Take a step back, it's probably not a technical problem. Why do you need to do this? Why do you have the conflicting needs of knowing the type at runtime only and knowing it at compile time?
You need to think about your requirements, not about the technical details.
I needed to dynamically load a single record from the database for each type in a list of known types, to print a test email when an admin is editing the template, so I did this:
List<object> args = new List<object>();
//...
//other stuff happens that isn't relevant to the OP, including adding a couple fixed items to args
//...
foreach (Type type in EmailSender.GetParameterTypes())
{
//skip anything already in the list
if (args.Any(a => a.GetType().IsAssignableFrom(type))) continue;
//dynamically get an item from the database for this type, safely assume that 1st column is the PK
string sql = dbContext.Set(type).Sql.Replace("SELECT", "SELECT TOP 1") + " ORDER BY 1 DESC";
var biff = dbContext.Set(type).SqlQuery(sql).AsNoTracking().ToListAsync().Result.First();
args.Add(biff);
}
Caveat: I know at least one record will exist for all entities I'm doing this for, and only one instance of each type may be passed to the email generator (which has a number of Debug.Asserts to test validity of implementation).
If you know the record ID you're looking for, rather than the entire table, you can use dbContext.Set(type).Find(). If you want the entire table of whatever type you've sussed out, you can just do this:
string sql = dbContext.Set(type).Sql; //append a WHERE clause here if needed/feasible, use reflection?
var biff = dbContext.Set(type).SqlQuery(sql).ToListAsync().Result;
Feels a little clunky, but it works. There is strangely no ToList without Async, but I can run synchronously here. In my case, it was essential to turn off Proxy Creation, but you look like you want to maintain a contextful state so you can write back to db. I'm doing a bunch of reflection later, so I don't really care about strong typing such a resulting collection (hence a List<object>). But once you have the collection (even just as object), you should be able to use System.Reflection as you are doing in your UPDATE sample code, since you know the type and can use SetValue with known/given property names in such a manner.
And I'm using .NET Framework, but hopefully this may translate over to .NET Core.
EDIT: tested and working:
public async Task<bool> MyMethod(string _type)
{
Type type = Type.GetType(_type);
var tableSet = _context.Set(type);
var list = await db.ToListAsync();
// do something
}
// pass the full namespace of class
var result = await MyMethod("Namespace.Models.MyClass")
IMPORTANT NOTE: your DbContext need to have the DbSet declared to work!
public class MyContext : DbContext
{
public DbSet<MyClass> MyClasses { get; set; }
}
I'm using a view returning Domains according to an id. The Domains column can be 'Geography' or can be stuffed domains 'Geography,History'. (In any way, the data returned is a VARCHAR)
In my C# code, I have a list containing main domains:
private static List<string> _mainDomains = new List<string>()
{
"Geography",
"Mathematics",
"English"
};
I want to filter my LINQ query in order to return only data related to one or many main Domain:
expression = i => _mainDomains.Any(s => i.Domains.Contains(s));
var results = (from v_lq in context.my_view
select v_lq).Where(expression)
The problem is I can't use the Any key word, nor the Exists keyword, since they aren't available in SQL. I've seen many solutions using the Contains keyword, but it doesn't fit to my problem.
What should I do?
You can use contains:
where i.Domains.Any(s => _mainDomains.Contains<string>(s.xxx))
Notice that the generic arguments are required (even if Resharper might tell you they are not). They are required to select Enumerable.Contains, not List.Contains. The latter one is not translatable (which I consider an error in the L2S product design).
(I might not have gotten the query exactly right for your data model. Please just adapt it to your needs).
I figured it out. Since I can't use the Any keyword, I used this function:
public static bool ContainsAny(this string databaseString, List<string> stringList)
{
if (databaseString == null)
{
return false;
}
foreach (string s in stringList)
{
if (databaseString.Contains(s))
{
return true;
}
}
return false;
}
So then I can use this expression in my Where clause:
expression = i => i.Domains.ContainsAny(_mainDomains);
Update:
According to usr, the query would return all the values and execute the where clause server side. A better solution would be to use a different approach (and not use stuffed/comma-separated values)
is there any way to share one LINQ query between two methods? I have quite long LINQ query that gets search results from database and I need to use this query to get results (some kind of list<>) -first method - and to get its count (int) - second method -. I don't want to copy this query in two separate methods and I can't return custom class object containing search results and records count (returned by this query). So what I want to do is to get LINQ query definition(or something like this?) but no the results set that I can use in other methods. Maybe there is another good way to do that. thanks for yout help ;)
the code look like this:
public ??? GetSearchResultsQuery(SearchRequest search_request)
{
var queryGetSearchResults = ....
return queryGetSearchResults;
}
public int GetSearchResultsCount(SearchRequest search_request)
{
return GetSearchResultsQuery(search_request).Count();
}
public List<SearchResults> GetSearchResults(SearchRequest search_request)
{
return GetSearchResultsQuery(search_request).Skip(search_request.startRowIndex).Take(search_request.maximumRows).ToList();
}
public IQueryable<SearchedForType> GetSearchResultsQuery(SearchRequest search_request)
{
var queryGetSearchResults = context.SearchedForTypes.Where(x => x == search_request.X);
... build up your search query ...
return queryGetSearchResults;
}
I have a series of about 30 lookup tables in my database schema, all with the same layout (and I would prefer to keep them as separate tables rather than one lookup table), and thus my Linq2SQL context has 30 entities for these lookup tables.
I have a standard class that I would use for CRUD operations on each of these 30 entites, for example:
public class ExampleAttributes : IAttributeList
{
#region IAttributeList Members
public bool AddItem(string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = new ExampleAttribute();
a.Name = Item;
a.SortOrder = SortOrder;
context.ExampleAttributes.InsertOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool DeleteItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
if (a == null)
return true;
// Make sure nothing is using it
int Count = (from m in context.Businesses
where m.ExampleAttributeId == a.Id
select m).Count();
if (Count > 0)
return false;
// Delete the item
context.ExampleAttributes.DeleteOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool UpdateItem(int Id, string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
a.Name = Item;
a.SortOrder = SortOrder;
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public String GetItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
var Attribute = (from a in context.ExampleAttributes
where a.Id == Id
select a).FirstOrDefault();
return Attribute.Name;
}
public Dictionary<int, string> GetItems()
{
Dictionary<int, string> Attributes = new Dictionary<int, string>();
MyDataContext context = ContextHelper.GetContext();
context.ObjectTrackingEnabled = false;
Attributes = (from o in context.ExampleAttributes orderby o.Name select new { o.Id, o.Name }).AsEnumerable().ToDictionary(k => k.Id, v => v.Name);
return Attributes;
}
#endregion
}
I could replicate this class 30 times with very minor changes for each lookup entity, but that seems messy somehow - so can this class be genericised so I can also pass it the type I want, and have it handle internally the type differences in the linq queries? That way, I have one class to make additions to, one class to bug fix et al - seems the way that it should be done.
UPDATE:
Andrews answer below gave me the option that I was really looking at while thinking about the question (passing the type in) but I need more clarification on how to genericise the linq queries. Can anyone clarify this?
Cheers
Moo
There are a couple things you can try.
One is to define an interface that has all the relevant fields that the thirty entity classes share. Then, you would be able to have each entity class implement this interface (let's call it IMyEntity) by doing something like
public partial class EntityNumber1 : IMyEntity
{
}
for each entity (where EntityNumber1 is the name of one of the entity classes). Granted, this is still thirty different definitions, but your CRUD operation class could then operate on IMyEntity instead of having to write a new class each time.
A second way to do this is simply to genericize the CRUD operation class, as you suggest:
public class ExampleAttributes<T> : IAttributeList
{
...
which allows you to use T as the type on which to operate. Granted, this might be easier in combination with the first method, since you would still have to check for the presence of the attributes and cast the entity to the appropriate type or interface.
Edit:
To check for the presence of the appropriate properties on the entity, you might need to use reflection methods. One way to check whether the given type T has a particular property might be to check for
typeof(T).GetProperties().OfType<PropertyInfo>().Count<PropertyInfo>(pi => pi.Name == "MyPropertyName" && pi.GetGetMethod().ReturnType == typeof(TypeIWant)) > 0
Of course, replace TypeIWant with the type you are expecting the property to be, and replace MyPropertyName with the name of the property for which you are checking.
Add a parameter to the constructors which specifies the type. Then you can work with it internally. One class, with perhaps a switch statement in the constructor.
For genericising a LINQ query, the biggest problem is that your DataContext has the collections based on type. There are a few ways this can be circumvented. You could try to access it using reflection, but that will require quite a bit of hacking and would pretty much destroy all efficiency that LINQ to SQL would provide.
The easiest way seems to be to use Dynamic LINQ. I have not used it personally, but it seems like it should support it. You can find more information in this thread: Generic LINQ query predicate?
and on http://aspalliance.com/1569_Dynamic_LINQ_Part_1_Using_the_LINQ_Dynamic_Query_Library.1
Maybe someone else can provide more information about this?
This isn't necessarily an answer to the question, but may be a solution to your problem. Have you considered generating all the classes that you need? T4 is built into Visual Studio, and can generate code for you. The link below describes it fairly broadly, but contains heaps of links for further information.
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
That way, you can define all the methods in one place, and generate the class files for your 30-odd lookup models. One place to make changes etc.
Maybe worth considering, and if not, still worth knowing about.
Is there anyway I can get the name of class property IntProperty?
public class ClassName
{
public static int IntProperty { get { return 0; } }
}
//something like below but I want to get the string of "IntProperty"
ClassName.IntProperty.GetType().Name
Basically what I want to do is to dynamically save property name string into the database, and later on retrieve it from the database and invoke the property dynamically.
Seems like what I am looking for is similar to duck typing I think.
Thanks!
UPDATED:
This is the actual code. This is more like a workflow kind of thing. But each task is defined as property of a class (class is used to group tasks).
public class ApplicationTask
{
public static Task<string> SendIncompleteNotification
{
get
{
return new Task<string>
(
a => Console.WriteLine("Sample Task")
, "This is a sample task which does nothing."
);
}
}
}
So, the code will be able to retrieve the full name of the class and property something like: namespace.ApplicationTask.SendIncompleteNotification and save this into the database. Later on, the code will read the string and dynamically create the task and pass it into another to execute.
With C#6.0 you can get it by
nameof(ClassName.IntProperty)
I think that the use of the GetProperty method in this case, is redundant, because you need to know the property name to call the method.
You could loop through your properties and extract its name:
foreach (PropertyInfo p in typeof(ClassName).GetProperties())
{
string propertyName = p.Name;
//....
}
The result of ClassName.IntProperty is just an integer value. As soon as it's executed and the result is returned, there's no trace of it having come from IntProperty.
If you're using .NET 3.5 you can use an expression tree instead, usually created via a lambda expression:
Expression<Func<int>> exp = () => ClassName.IntProperty;
You can then compile and execute the expression and separately find out what it's doing (retrieving IntProperty in this case). I'm not really sure whether this is suitable for what you want to do though.
If you do work out how to save the property name in the database, then GetProperty is the way to go on the retrieval front.
Perhaps if you could give more context in the question in terms of how you want to use this, we could help more. You've shown just an expression - if you could show it in terms of where you'd be using it, that would be great.
EDIT: You've expanded the property, but not how it's being called. Do you need to call it directly, rather than just fetching the list of properties using Type.GetProperties and storing the list of property names in the database?
Again, if you could show the code which calls the property, and how you want it to interact with the database, we may be able to make more progress.
Type objectType = this.GetType();
PropertyInfo property = objectType.GetProperty("intProperty");
System.Console.Write(property.Name);
Is this what you need?
You can simply use nameof(ClassName.IntProperty)
It will give you "IntProperty"
I came across this, and it seems very helpful for getting property name. (C++)
#define getVarName(varName,holder) sprintf(holder, "%s", #varName)
int main() {
int var = 100; // just any type of identifier
char name[100]; // it will get the variables name
getVarName(var, name);
puts(name);
return 0;
}
ref: http://zobayer.blogspot.com/2010/05/c-fun-get-variables-name.html