Executing stored procedures and getting the output - entity-framework

I am trying to read the size of my database, and I can do this in SQL Server - but how do I run the following code in Entity Framework and get the output?
USE Impro_V2
GO
sp_spaceused
GO
or
EXEC sp_helpdb N'Impro_V2';
Using context.Database.ExecuteSqlCommand I get a result of "-1". I am not even sure whether that is failed.
How do run code like that?

The answer is here:
How to know the physical size of the database in Entity Framework?
The code is simple:
var ef = new MyDbContext();
var sqlConn = ef.Database.Connection as SqlConnection;
var cmd = new SqlCommand("sp_spaceused")
{
CommandType = System.Data.CommandType.StoredProcedure,
Connection = sqlConn as SqlConnection
};
var adp = new SqlDataAdapter(cmd);
var dataset = new DataSet();
sqlConn.Open();
adp.Fill(dataset);
sqlConn.Close();
// example read
foreach (DataTable table in dataset.Tables)
{
foreach (DataRow row in table.Rows)
{
foreach (DataColumn col in table.Columns)
{
console.write(row[icol].tostring());
etc

Related

EF Core multiple datasets

I am new to EF and want to return multiple datasets (like we do in stored procedures) in one database trip. I have 3 dropdowns to populate on my form plus the main page fields (which would be another dataset)
Any help would be appreciated.
Thanks
in this MSDN link sample you can find the full solution
using (var db = new BloggingContext())
{
// If using Code First we need to make sure the model is built before we open the connection
// This isn't required for models created with the EF Designer
db.Database.Initialize(force: false);
// Create a SQL command to execute the sproc
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[GetAllBlogsAndPosts]";
try
{
db.Database.Connection.Open();
// Run the sproc
var reader = cmd.ExecuteReader();
// Read Blogs from the first result set
var blogs = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly);
foreach (var item in blogs)
{
Console.WriteLine(item.Name);
}
// Move to second result set and read Posts
reader.NextResult();
var posts = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Post>(reader, "Posts", MergeOption.AppendOnly);
foreach (var item in posts)
{
Console.WriteLine(item.Title);
}
}
finally
{
db.Database.Connection.Close();
}
}

nDepend - how to modify "JustMyCode" queries using nDepend API?

My goal is to modify "JustMyCode" queries using nDepend API. I am using code like:
var justMyCodeGroup = prj.CodeQueries.CodeQueriesSet.ChildGroups.Single(x => x.Name.Contains("JustMyCode"));
var originalQuery = justMyCodeGroup.ChildQueries
.Single(x => x.QueryString.Contains("Discard generated Types from JustMyCode"));
var changedQuery = originalQuery.Controller.CreateQuery(originalQuery.IsActive,
query,
originalQuery.
DisplayStatInReport,
originalQuery.DisplayListInReport,
originalQuery.DisplaySelectionViewInReport,
originalQuery.IsCriticalRule);
var justMyCodeGroupWithModifiedQuery = justMyCodeGroup.ReplaceQuery(originalQuery, changedQuery);
prj.CodeQueries.CodeQueriesSet.ReplaceGroup(justMyCodeGroup, justMyCodeGroupWithModifiedQuery);
However, when I run the code above I get ArgumentException with message:
newGroup.Controller is different than this groupOfGroups.Controller
Any help ?
Update 1:
I also tried code:
var justMyCodeGroup = prj.CodeQueries.CodeQueriesSet.ChildGroups.Single(x => x.Name.Contains("JustMyCode"));
var originalQuery = justMyCodeGroup.ChildQueries
.Single(x => x.QueryString.Contains("Discard generated Types from JustMyCode"));
var changedQuery = originalQuery.Controller.CreateQuery(originalQuery.IsActive,
query,
originalQuery.
DisplayStatInReport,
originalQuery.DisplayListInReport,
originalQuery.DisplaySelectionViewInReport,
originalQuery.IsCriticalRule);
var justMyCodeGroupWithModifiedQuery = justMyCodeGroup.ReplaceQuery(originalQuery, changedQuery);
var newQueries = new List<IQuery>();
foreach (var q in justMyCodeGroup.ChildQueries)
{
if (q.QueryString.Contains("Discard generated Types from JustMyCode"))
{
continue;
}
newQueries.Add(prj.CodeQueries.CodeQueriesSet.Controller.CreateQuery(q.IsActive, q.QueryString,
q.DisplayStatInReport, q.DisplayListInReport, q.DisplaySelectionViewInReport, q.IsCriticalRule));
}
newQueries.Add(prj.CodeQueries.CodeQueriesSet.Controller.CreateQuery(originalQuery.IsActive, query, originalQuery.DisplayStatInReport, originalQuery.DisplayListInReport, originalQuery.DisplaySelectionViewInReport, originalQuery.IsCriticalRule));
var newGroup = prj.CodeQueries.CodeQueriesSet.Controller.CreateGroup(justMyCodeGroup.Name,
justMyCodeGroup.IsActive, justMyCodeGroup.ShownInReport, newQueries, new List<IGroup>());
prj.CodeQueries.CodeQueriesSet.RemoveGroup(justMyCodeGroup);
prj.CodeQueries.CodeQueriesSet.AddGroup(newGroup);
Right now, RemoveGroup throws exception:
this group of groups doesn't contain groupToRemove.
Update 2:
And I also wonder, why does this code return false ?
var justMyCodeGroup = prj.CodeQueries.CodeQueriesSet.ChildGroups.Single(x => x.Name.Contains("JustMyCode"));
prj.CodeQueries.CodeQueriesSet.ContainsGroup(justMyCodeGroup)
Refer to the PowerTools source file:
$NDependInstallDir$\NDepend.PowerTools.SourceCode\CQL2CQLinq\CQL2CQLinqPowerTool.cs
This PowerTools convert code queries written with old CQL syntax into code queries written with new CQLinq syntax, hence it loads the queries set from a project, update CQL queries, and then save the new queries set in the project.
The queriesController is gathered this way...
var queriesSet = project.CodeQueries.CodeQueriesSet;
var queriesController = queriesSet.Controller;
... and then used this way to modify the queries set:
queriesController.DoUpdateQueryObject(query, newQuery);

Returning a DataTable using Entity Framework ExecuteStoreQuery

I am working with a system that has many stored procedures that need to be displayed. Creating entities for each of my objects is not practical.
Is it possible and how would I return a DataTable using ExecuteStoreQuery ?
public ObjectResult<DataTable> MethodName(string fileSetName) {
using (var dataContext = new DataContext(_connectionString))
{
var returnDataTable = ((IObjectContextAdapter)dataContext).ObjectContext.ExecuteStoreQuery<DataTable>("SP_NAME","SP_PARAM");
return returnDataTable;
}
Yes it's possible, but it should be used for just dynamic result-set or raw SQL.
public DataTable ExecuteStoreQuery(string commandText, params Object[] parameters)
{
DataTable retVal = new DataTable();
retVal = context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();
return retVal;
}
Edit: It's better to use classical ADO.NET to get the data model rather than using Entity Framework because most probably you cannot use DataTable even if you can run the method: context.ExecuteStoreQuery<DataTable>(commandText, parameters).FirstOrDefault();
ADO.NET Example:
public DataSet GetResultReport(int questionId)
{
DataSet retVal = new DataSet();
EntityConnection entityConn = (EntityConnection)context.Connection;
SqlConnection sqlConn = (SqlConnection)entityConn.StoreConnection;
SqlCommand cmdReport = new SqlCommand([YourSpName], sqlConn);
SqlDataAdapter daReport = new SqlDataAdapter(cmdReport);
using (cmdReport)
{
SqlParameter questionIdPrm = new SqlParameter("QuestionId", questionId);
cmdReport.CommandType = CommandType.StoredProcedure;
cmdReport.Parameters.Add(questionIdPrm);
daReport.Fill(retVal);
}
return retVal;
}
No, I don't think that'll work - Entity Framework is geared towards returning entities and isn't meant to return DataTable objects.
If you need DataTable objects, use straight ADO.NET instead.
This method uses the connection string from the entity framework to establish an ADO.NET connection, to a MySQL database in this example.
using MySql.Data.MySqlClient;
public DataSet GetReportSummary( int RecordID )
{
var context = new catalogEntities();
DataSet ds = new DataSet();
using ( MySqlConnection connection = new MySqlConnection( context.Database.Connection.ConnectionString ) )
{
using ( MySqlCommand cmd = new MySqlCommand( "ReportSummary", connection ) )
{
MySqlDataAdapter adapter = new MySqlDataAdapter( cmd );
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.SelectCommand.Parameters.Add( new MySqlParameter( "#ID", RecordID ) );
adapter.Fill( ds );
}
}
return ds;
}
Yes it can easily be done like this:
var table = new DataTable();
using (var ctx = new SomeContext())
{
var cmd = ctx.Database.Connection.CreateCommand();
cmd.CommandText = "Select Col1, Col2 from SomeTable";
cmd.Connection.Open();
table.Load(cmd.ExecuteReader());
}
By the rule, you shouldn't use a DataSet inside a EF application. But, if you really need to (for instance, to feed a report), that solution should work (it's EF 6 code):
DataSet GetDataSet(string sql, CommandType commandType, Dictionary<string, Object> parameters)
{
// creates resulting dataset
var result = new DataSet();
// creates a data access context (DbContext descendant)
using (var context = new MyDbContext())
{
// creates a Command
var cmd = context.Database.Connection.CreateCommand();
cmd.CommandType = commandType;
cmd.CommandText = sql;
// adds all parameters
foreach (var pr in parameters)
{
var p = cmd.CreateParameter();
p.ParameterName = pr.Key;
p.Value = pr.Value;
cmd.Parameters.Add(p);
}
try
{
// executes
context.Database.Connection.Open();
var reader = cmd.ExecuteReader();
// loop through all resultsets (considering that it's possible to have more than one)
do
{
// loads the DataTable (schema will be fetch automatically)
var tb = new DataTable();
tb.Load(reader);
result.Tables.Add(tb);
} while (!reader.IsClosed);
}
finally
{
// closes the connection
context.Database.Connection.Close();
}
}
// returns the DataSet
return result;
}
In my Entity Framework based solution I need to replace one of my Linq queries with sql - for efficiency reasons.
Also I want my results in a DataTable from one stored procedure so that I could create a table value parameter to pass into a second stored procedure. So:
I'm using sql
I don't want a DataSet
Iterating an IEnumerable probably isn't going to cut it - for efficiency reasons
Also, I am using EF6, so I would prefer DbContext.SqlQuery over ObjectContext.ExecuteStoreQuery as the original poster requested.
However, I found that this just didn't work:
_Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();
This is my solution. It returns a DataTable that is fetched using an ADO.NET SqlDataReader - which I believe is faster than a SqlDataAdapter on read-only data. It doesn't strictly answer the question because it uses ADO.Net, but it shows how to do that after getting a hold of the connection from the DbContext
protected DataTable GetDataTable(string sql, params object[] parameters)
{
//didn't work - table had no columns or rows
//return Context.Database.SqlQuery<DataTable>(sql, parameters).FirstOrDefault();
DataTable result = new DataTable();
SqlConnection conn = Context.Database.Connection as SqlConnection;
if(conn == null)
{
throw new InvalidCastException("SqlConnection is invalid for this database");
}
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddRange(parameters);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
result.Load(reader);
}
return result;
}
}
The easiest way to return a DataTable using the EntityFramework is to do the following:
MetaTable metaTable = Global.DefaultModel.GetTable("Your EntitySetName");
For example:
MetaTable metaTable = Global.DefaultModel.GetTable("Employees");
Maybe your stored procedure could return a complex type?
http://blogs.msdn.com/b/somasegar/archive/2010/01/11/entity-framework-in-net-4.aspx

Are there any other way to fill a Datatable in ADO.Net without using dataadaptor.Fill method?

Are there any other fast way to fill a Data table in ADO.Net without using Data adaptor.Fill method?
Yes, you can. Here a short example:
var results = new DataTable();
using(var connection = new SqlConnection(...))
using(var command = connection.CreateCommand())
{
command.Text = "sql statement";
var parameter = command.CreateParameter();
parameter.Name = "name";
parameter.Value = aValue;
command.Parameters.Add(parameter);
connection.Open();
results.Load(command.ExecuteReader());
}
return results;
If you just need to create a data table, e.g. for storing data not comming from a database, then you can create a new DataTable and populate it you self, like this:
var x = new DataTable("myTable");
x.Columns.Add("Field1", typeof(string));
x.Columns.Add("Field2", typeof(string));
x.Columns.Add("Field3", typeof(int));
x.Rows.Add("fred", "hugo", 1);
x.Rows.Add("fred", "hugo", 2);
x.Rows.Add("fred", "hugo", 3);
You can manually create DataTables and their content using the methods of the various types involved.
This does take a little code but is possible (I've done it from a custom serialisation in .NET 1.1 to populate a data source for a control that needed a DataSet).
[A more specific answer would really require knowing why you are interested in this.]

How to learn ADO.NET

I need to learn ADO.NET to build applications based on MS Office. I have read a good deal about ADO.NET in the MSDN Library, but everything seems rather messy to me.
What are the basics one must figure out when using ADO.NET? I think a few key words will suffice to let me organize my learning.
There are three key components (assuming ur using SQL server):
SQLConnection
SqlCommand
SqlDataReader
(if you're using something else, replace Sql with "Something", like MySqlConnection, OracleCommand)
Everything else is just built on top of that.
Example 1:
using (SqlConnection connection = new SqlConnection("CONNECTION STRING"))
using (SqlCommand command = new SqlCommand())
{
command.commandText = "SELECT Name FROM Users WHERE Status = #OnlineStatus";
command.Connection = connection;
command.Parameters.Add("#OnlineStatus", SqlDbType.Int).Value = 1; //replace with enum
connection.Open();
using (SqlDataReader dr = command.ExecuteReader))
{
List<string> onlineUsers = new List<string>();
while (dr.Read())
{
onlineUsers.Add(dr.GetString(0));
}
}
}
Example 2:
using (SqlConnection connection = new SqlConnection("CONNECTION STRING"))
using (SqlCommand command = new SqlCommand())
{
command.commandText = "DELETE FROM Users where Email = #Email";
command.Connection = connection;
command.Parameters.Add("#Email", SqlDbType.VarChar, 100).Value = "user#host.com";
connection.Open();
command.ExecuteNonQuery();
}
Another way of getting a command object is to call connection.CreateCommand().
That way you shouldn't have to set the Connection property on the command object.