What I have:
DB with data and connection to it by
public class VMMExtDBContext : DbContext {...}
inside this perfectly works something like this:
public DbSet<VirtualMachine> VirtualMachines { get; set; }
now I need a run query that perfectly run from MSSMS:
select SUM(CPUCount), SUM(RAMSizeGB), SUM(PrimaryHDDVolumeGB)
from TempVMs
where VMCloudID='f51b73b5-fdb3-4af2-956b-b27fccc5e19d'
So I wrote code:
public QuotaPresenter(VMMExtDBContext db, Guid CloudID)
{
string entitySQL = "select SUM(CPUCount), SUM(RAMSizeGB), SUM(PrimaryHDDVolumeGB) from TempVMs where VMCloudID='"+CloudID.ToString()+"'";
//or = "select SUM(CPUCount), SUM(RAMSizeGB), SUM(PrimaryHDDVolumeGB) from dbo.TempVMs where VMCloudID='"+CloudID.ToString()+"'";
var objectContext = (db as IObjectContextAdapter).ObjectContext;
var query=objectContext.CreateQuery<UsedQuotaValue>(entitySQL);
query.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var QuoteValues=query.ToList(); //<--Exception here
if (QuoteValues.Count > 0) {
//На случай если нет ни одной виртуальной машины - оставляем по нулям
UQV.CPU = QuoteValues[0].CPU;
UQV.RAM = QuoteValues[0].RAM;
UQV.PrimaryHDDGB = QuoteValues[0].PrimaryHDDGB;
}
}
And when I run got an exception:
[System.Data.EntitySqlException]
'TempVMs' could not be resolved in
the current scope or context. Make sure that all referenced variables
are in scope, that required schemas are loaded, and that namespaces
are referenced correctly. Near simple identifier, line 1, column
68.
What am I missing?
I think the problem is you are missing the schema indentifier from the table name. And the query will not work without a group by statement if i am correct.
I think the problem is that you are trying to use regular transact-sql in place of entity sql, and they actually are not the same. Take a look at Aggregate Functions, this may help you (I cannot test it myself)
SELECT VALUE SqlServer.SUM(p.ListPrice)
FROM AdventureWorksEntities.Products as p
Related
Cross posted on MSDN
We use manual code first Entity Framework for System.Data.Sqlite
So when creating a new entity, we manually create the table, the c# object, and add the DbSet to our context.
I have a very simple object created and I am getting this error when trying to query the context. I have checked the column names and data types many times but I don't see a mismatch here. Also there are no foreign key relationships defined even though the fields have id in the name. Just a standalone table.
The weirdest part is that I can add a new entity to the context, save changes, and it will be persisted to the db. However in the next line when trying to retrieve the entities I get The entity set is not defined in the entity container error. I have also noticed that if I hover over an instantiated context, all the other db sets will have the EF SQL such as SELECT EXTENT1.myCol as myCol, but the department_resources set just says {System.Data.Entity.DbSet<department_resource>}.
Any ideas on what the issue is here?
Below are excerpts of my files:
DDL
CREATE TABLE department_resources (
dep_res_key VARCHAR PRIMARY KEY,
department_id INT NOT NULL,
resource_id INT NOT NULL);
department_resource.cs
[Table("department_resources")]
public class department_resource
{
[Key]
public string dep_res_key { get; set; }
public int department_id { get; set; }
public int resource_id { get; set; }
}
MyContext.cs
public class MyContext : DbContext
{
public DbSet<department_resource> department_resources { get; set; }
}
Sample Usage
using (MyContext db = new MyContext())
{
db.department_resources.Add(new department_resource()
{ dep_res_key = "anID",
resource_id = 22,
department_id = 23 }); // Works
db.SaveChanges(); // Also works. Even persists to db
var foo = from r in db.department_resources
select r.resource_id; // Doesn't work. Will error as soon as I try to use foo. Like assigning to a combo box item source. Or even just enumerating the results
var bar = db.department_resources; // Also doesn't work.
}
The issue is with deferred execution. Although you're assigning foo and bar within your using block, they're not getting evaluated until they're actually used, after MyContext has been disposed.
You need to force them to evaluated within your using block. e.g. by converting the results to lists.
Also I notice you've declared them as vars within your using block. They'll need to be defined outside of it to be able to use them outside (perhaps you just did this in your sample to simplify?)
List<int> foo;
List<department_resource> bar;
using (MyContext db = new MyContext())
{
db.department_resources.Add(new department_resource()
{ dep_res_key = "anID",
resource_id = 22,
department_id = 23 }); // Works
db.SaveChanges(); // Also works. Even persists to db
foo = (from r in db.department_resources
select r.resource_id).ToList();
bar = db.department_resources.ToList();
}
From MSDN
the query variable itself only stores the query commands. The actual
execution of the query is deferred until you iterate over the query
variable in a foreach statement. This concept is referred to as
deferred execution
Forcing Immediate Execution
Queries that perform aggregation functions over a range of source elements must first iterate over
those elements. Examples of such queries are Count, Max, Average, and
First. These execute without an explicit foreach statement because the
query itself must use foreach in order to return a result. Note also
that these types of queries return a single value, not an IEnumerable
collection.
You can also force execution by putting the foreach loop immediately
after the query expression. However, by calling ToList or ToArray you
also cache all the data in a single collection object.
I'm trying to accomplish 2 things with the below snippet of code (from ApplicationDataService.lsml.cs in the server project of my Lightswitch 2013 solution).
partial void Query1_PreprocessQuery(ref IQueryable<CandidateBasic> query)
{
query = from item in query where item.CreatedBy == this.Application.User.Name select item;
}
partial void CandidateBasics_Validate(CandidateBasic entity, EntitySetValidationResultsBuilder results)
{
var newcandidateCount = this.DataWorkspace.ApplicationData.Details.GetChanges().AddedEntities.OfType<CandidateBasic>().Count();
var databasecandidateCount = this.CandidateBasics.GetQuery().Execute().Count();
const int maxcandidateCount = 1;
if (newcandidateCount + databasecandidateCount > maxcandidateCount)
{
results.AddEntityError("Error: you are only allowed to have one candidate record");
}
}
Firstly, I want to make sure each user can only see things that he has made. This, together with a preprocess query on the table in question, works perfectly.
The next bit is designed to make sure that each user can only create one record in a certain table. Unfortunately, it seems to be looking at the whole table, and not the query I made that shows only the user's own records.
How can I get that second bit of code to limit only the user's own records, and not the global table?
You're not actually calling that query though are you? Your query is called Query1 based on the code provided yet you don't seem to be calling it. I'd do something like:
int count = DataWorkspace.ApplicationData.Query1().Count();
`Hi,
Can somebody please give me a pointer on this? I have 8 servers each with 8 databases which look identical exept server/database name. We are talking thousands of tables.
I create my data contexts with sqlmetal.exe
After creating my data contexts, I import them into the application and then I run comparison scripts over the databases to compare results.
My problem is dynamically switching between data contexts.
Datacontext.DAL.DUK1 duk1sdi = new Datacontext.DAL.DUK1(connectionString);
Datacontext.DAL.DUK3 duk3sdi = new Datacontext.DAL.DUK3(connectionString);
string fromOne = runQuery(duk1sdi);
string fromThree = runQuery(duk3sdi);
public static string runQuery(DataContext duk)
{
var query =
from result in duk.TableA
select result.Total;
string returnString = query;
return returnString;
}
I have no problem with the query running when the duk is predefined, however how do I define and pass the datacontext to the function?
The error I get is:
Error 1 'System.Data.Linq.DataContext' does not contain a definition
for 'TableA' and no extension method 'TableA' accepting a first
argument of type 'System.Data.Linq.DataContext' could be found (are
you missing a using directive or an assembly reference?)
You could use the GetTable<T> method, where T is the type of the table, e.g. TableA.
public static string runQuery(DataContext duk) {
var table = duk.GetTable<TableA>();
var query = from result in table select result.Total;
...
}
However, all types of TableA will need to be the same type, strictly (I'm pretty sure).
Otherwise you would need to literally branch the logic for the handling of each context. Since you can extend your DataContext instances (in general, maybe not in your specific case) then you could have them share an interface that exposes a collection property of TableA, but you would need a higher level context wrapper to pass around then - unless you pass around the collection by altering the method signature.
You can use interfaces. Check this answer, but be sure to script the interfaces using a .tt file with the amount of tables you have.
Edit:
If you have generated contexts which you want to use interchangeably in a reusable method, you have the problem that the generated TableA classes are not reusable, since they are different types (even though the names may match, but that doesn't make them equal). Therefore you need to abstract the actual types, and one way to do this, is to use interfaces. You build your reusable method around an interface which abstracts the specific context-type and table-type. The downside is that you have to implement the interfaces on the generated contexts and tabletypes. This though is something you can solve using a .tt script.
Pseudo code:
// Define interface for table
public interface ITableA {
// ... properties
}
// Define interface for context
public interface IMyContext {
IQueryable<ITableA> TableA { get; }
}
// Extend TableA from DUK1
public partial class TableA: ITableA {
}
// Extend DUK1
public partial class Datacontext.DAL.DUK1: IMyContext {
IQueryable<ITableA> IMyContext.TableA {
get { return TableA; }
}
}
// Same for DUK3 and TableA FROM DUK3
// Finally, your code
Datacontext.DAL.DUK1 duk1sdi = new Datacontext.DAL.DUK1(connectionString);
Datacontext.DAL.DUK3 duk3sdi = new Datacontext.DAL.DUK3(connectionString);
string fromOne = runQuery(duk1sdi);
string fromThree = runQuery(duk3sdi);
public static string runQuery(IMyContext duk) {
// Note: method accepts interface, not specific context type
var query = from result in duk.TableA
select result.Total;
string returnString = query;
return returnString;
}
If your schema is identical between databases, why script the dbml for all of them? Just create one context with it's associated classes and dynamically switch out the connection string when instantiating the context.
var duk1sdi = new Datacontext.DAL.DUK1(connectionString1);
var duk3sdi = new Datacontext.DAL.DUK1(connectionString2);
Thanks, guys, I think I found the simplist solution for me based a bit of both your answers and by RTFM (Programming Microsoft Linq in Microsoft .NET Framework 4 by Paulo Pialorsi and Marco Russo)
In this way I don't have to use the large DBML files. It is a shame because I'm going to have to create hundreds of tables in this way, but I can now switch between connection strings on the fly.
First I create the table structure. (outside the program code block)
[Table(Name = "TableA")]
public class TableA
{
[Column] public int result;
}
Then I define the table for use:
Table<TableA> TableA = dc.GetTable<TableA>();
And then I can query from it:
var query =
from result in TableA
select TableA.result;
I have this query in sql and it works fine:
update userinfo set Interest = 0.98 where userid = 313
And I want to do it in linq, so I prepared the following:
public class TableDataDTO
{
public string Columnname { get; set; }
public string Value { get; set; }
public Type DataType { get; set; }
}
Implementation:
TableDataDTO tableData = new TableDataDTO();
tableData.Columnname = "Interest";
tableData.Value = "0.98";
using (dbase instance = new dbase())
{
string predicate = string.Format("it.UserID=={0} set it.{1}={2}" ,
313, tableData.Columnname, tableData.Value);
var uinfo = instance.userinfoes.Where(predicate).FirstOrDefault();
if (uinfo != null)
{
instance.SaveChanges();
return true;
}
}
But it gives me this error:
The query syntax is not valid. Near keyword 'SET'
I will be dealing with different columns, so I need to use linq predicates to minimize the code.
I don't like using any plugins to make this. Hope someone could help.
Edit
I think what I mean is "How to update data in using Dynamic linq"
Edit2
So this is the real scenario. Users/Client can update their information, e.g. First name, Last name, Address, City.. etc.. not at once but capable of updating the info one by one.
So what does it mean? Ok I can create a method that can update the First Name, next is the Last Name, Address and so one.. But if I do this, it will consume a lot of code. If only if there is a code in linq that can do what SQL does in updating data, then I would just need a code that gets the column name and set its value. Hope I'd explain it well.
Edit3
I have changed the question from How to update data in linq using predicates? to How to update column data using sql query in linq? for I misunderstood the real meaning of predicate.
Your predicate should just be the where part of the query (a predicate just returns true or false). Try this:
instance.userinfoes.Where(user => user.userid == 313).First().Interest = 0.98;
You can structure LINQ similar to how you'd structure SQL. Through a combination of Where and ForEach you should be able to update all the rows you need. I.e:
instance.userinfoes.Where(it => it.UserId == 313).ToList()
.ForEach(
it => it.Interest = 0.98M
);
There's not really any way to write SQL-like queries as text and pass them to regular LINQ as far as I know.
See this question for more solutions:
Update all objects in a collection using LINQ
I wanted to use linq as so:
MyDBEntities context = new MyDBEntities();
context.MyTable.Where(i => MyMethod(i.column, valueToTest).ToList();
with
public bool MyMethod(Object a, Object b)
but apparently using such a method with isn't possible
so I was hopping I could use the methode in a stored procedure I would be able to call with linq
do you think is it possible ?
Generally it is possible to create C# function and use it in SQL Server (2005 and newer) but it is not so simple - you must use SQL CLR which means separate project for your function, special references, special types, etc. At last you must deploy the assembly to SQL server to be able to use the function in SQL. General documentation also covering how to create custom function:
Creating SQL Server Objects in Managed Code
Once you have your function on SQL server you can use it within stored procedure and you can use it within query. I'm actually not sure if you can import these functions into Linq-to-sql or EF model and use them in Linq-to-sql or Linq-to-entities queries.
Take a look here for a complete sample:
Calling custom methods in LINQ-to-SQL
I hope I understand you correctly.
Let's say that MyTable is a database table that contains the columns Name, and Address
Here's how you would get a value back whether the results contain the specified value you passed.
public void SomeMethod()
{
MyTable table= new MyTable();
bool b= MyMethod(table.Name, "Fred");
if(b)
//Do something
else
//Do something else
}
public bool MyMethod(MyTable a, object value)
{
using(var context= new MyDBEntities())
{
return context.MyTable.Where(i => a == value).Any();
}
}
This is what the database table 'MyTable' looks like behind the scenes.(the data context generated this)
public class MyTable
{
public string Name { get; set; }
public string Address { get; set; }
}
So you can see in the first method I pass table.Name to MyMethod, that's only possible because MyTable has a pubic property called Name. Also notice that we are using type Object for the value, as the parameter could an int, a string, a date time, who knows.
Note: This is untested code, but should get off to right track if I understand you correctly.