EF 6 - Stored Procedure Duplicate Result Column - sql-server

I'm in the process of migrating from a legacy system. The database cannot be modified - including adding/modifying stored procedures.
I've added a stored procedure to an EDMX model successfully, it generated the following code:
public virtual ObjectResult<sp_GetUserInfoByUID_Result> sp_GetUserInfoByUID(Nullable<System.Guid> sessionID, Nullable<System.Guid> userUID)
{
var sessionIDParameter = sessionID.HasValue ?
new ObjectParameter("SessionID", sessionID) :
new ObjectParameter("SessionID", typeof(System.Guid));
var userUIDParameter = userUID.HasValue ?
new ObjectParameter("userUID", userUID) :
new ObjectParameter("userUID", typeof(System.Guid));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<sp_GetUserInfoByUID_Result>("sp_GetUserInfoByUID", sessionIDParameter, userUIDParameter);
}
However, I get the following runtime error:
The data reader is incompatible with the specified 'MyApp.Repository.sp_GetUserInfoByUID_Result'. A member of the type, 'useraccount_uid1', does not have a corresponding column in the data reader with the same name.
So it looks like EF generated two mappings: useraccount_uid and useraccount_uid1. This is because the stored procedure returns a table with two columns named useraccount_uid.
Is there a way to get round this in the EF model?

Turns out the solution was really simple, I'd just overlooked how EF modeled stored procedures. When you add a stored procedure to the Model, by default it actually adds a couple of references.
A mapping from the model to the basic function in the DB - you cannot edit these mappings.
A "Function Import" - this is the part which maps result sets to code models.
So all I had to was look for the Function Imports folder in the EDMX Model Browser. In here the stored procedure was listed. If you right-click on the function you'll see the "Function Import Mapping" option. This will open the Mappings Detail window. Here I could simply correct the column naming.

Related

How to find a MoveTo destination filled by database?

I could need some help with a Anylogic Model.
Model (short): Manufacturing scenario with orders move in a individual route. The workplaces (WP) are dynamical created by simulation start. Their names, quantity and other parameters are stored in a database (excel Import). Also the orders are created according to an import. The Agent population "order" has a collection routing which contains the Workplaces it has to stop in the specific order.
Target: I want a moveTo block in main which finds the next destination of the agent order.
Problem and solution paths:
I set the destination Type to agent and in the Agent field I typed a function agent.getDestination(). This function is in order which returns the next entry of the collection WP destinationName = routing.get(i). With this I get a Datatype error (while run not compiling). I quess it's because the database does not save the entrys as WP Type but only String.
Is there a possiblity to create a collection with agents from an Excel?
After this I tried to use the same getDestination as String an so find via findFirst the WP matching the returned name and return it as WP. WP targetWP = findFirst(wps, w->w.name == destinationName);
Of corse wps (the population of Workplaces) couldn't be found.
How can I search the population?
Maybe with an Agentlink?
I think it is not that difficult but can't find an answer or a solution. As you can tell I'm a beginner... Hope the description is good an someone can help me or give me a hint :)
Thanks
Is there a possiblity to create a collection with agents from an Excel?
Not directly using the collection's properties and, as you've seen, you can't have database (DB) column types which are agent types.1
But this is relatively simple to do directly via Java code (and you can use the Insert Database Query wizard to construct the skeleton code for you).
After this I tried to use the same getDestination as String an so find via findFirst the WP matching the returned name and return it as WP
Yes, this is one approach. If your order details are in Excel/the database, they are presumably referring to workplaces via some String ID (which will be a parameter of the workplace agents you've created from a separate Excel worksheet/database table). You need to use the Java equals method to compare strings though, not == (which is for comparing numbers or whether two objects are the same object).
I want a moveTo block in main which finds the next destination of the agent order
So the general overall solution is
Create a population of Workplace agents (let's say called workplaces in Main) from the DB, each with a String parameter id or similar mapped from a DB column.
Create a population of Order agents (let's say called orders in Main) from the DB and then, in their on-startup action, set up their collection of workplace IDs (type ArrayList, element class String; let's say called workplaceIDsList) using data from another DB table.
Order probably also needs a working variable storing the next index in the list that it needs to go to (so let's say an int variable nextWorkplaceIndex which starts at 0).
Write a function in Main called getWorkplaceByID that has a single String argument id and returns a Workplace. This gets the workplace from the population that matches the ID; a one-line way similar to yours is findFirst(workplaces, w -> w.id.equals(id)).
The MoveTo block (which I presume is in Main) needs to move the Order to an agent defined by getWorkplaceByID(agent.workplaceIDsList.get(nextWorkplaceIndex++)). (The ++ bit increments the index after evaluating the expression so it is ready for the next workplace to go to.)
For populating the collection, you'd have two tables, something like the below (assuming using strings as IDs for workplaces and orders):
orders table: columns for parameters of your orders (including some String id column) other than the workplace-list. (Create one Order agent per row.)
order_workplaces table: columns order_id, sequence_num and workplace_id (so with multiple rows specifying the sequence of workplace IDs for an order ID).
In the On startup action of Order, set up the skeleton query code via the Insert Database Query wizard as below (where we want to loop through all rows for this order's ID and do something --- we'll change the skeleton code to add entries to the collection instead of just printing stuff via traceln like the skeleton code does).
Then we edit the skeleton code to look like the below. (Note we add an orderBy clause to the initial query so we ensure we get the rows in ascending sequence number order.)
List<Tuple> rows = selectFrom(order_workplaces)
.where(order_workplaces.order_id.eq(id))
.orderBy(order_workplaces.sequence_num.asc())
.list();
for (Tuple row : rows) {
workplaceIDsList.add(row.get(order_workplaces.workplace_id));
}
1 The AnyLogic database is a normal relational database --- HSQLDB in fact --- and databases only understand their own specific data types like VARCHAR, with AnyLogic and the libraries it uses translating these to Java types like String. In the user interface, AnyLogic makes it look like you set the column types as int, String, etc. but these are really the Java types that the columns' contents will ultimately be translated into.
AnyLogic does support columns which have option list types (and the special Code type column for columns containing executable Java code) but these are special cases using special logic under the covers to translate the column data (which is ultimately still a string of characters) into the appropriate option list instance or (for Code columns) into compiled-on-the-fly-and-then-executed Java).
Welcome to Stack Overflow :) To create a Population via Excel Import you have to create a method and call Code like this. You also need an empty Population.
int n = excelFile.getLastRowNum(YOUR_SHEET_NAME);
for(int i = FIRST_ROW; i <= n; i++){
String name = excelFile.getCellStringValue(YOUR_SHEET_NAME, i, 1);
double SEC_PARAMETER_TO_READ= excelFile.getCellNumericValue(YOUR_SHEET_NAME, i, 2);
WP workplace = add_wps(name, SEC_PARAMETER_TO_READ);
}
Now if you want to get a workplace by name, you have to create a method similar to your try.
Functionbody:
WP workplaceToFind = wps.findFirst(w -> w.name.equals(destinationName));
if(workplaceToFind != null){
//do what ever you want
}

SQLALchemy - cannot reflect a SQL Server DB running on Amazon RDS

My code is simple:
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
db.metadata.reflect()
And it throws no errors. However, when I inspect the metadata after this reflection, it returns an empty immutabledict object.
The parameters in my connection string is 100% correct and the code works with non-RDS databases.
It seems to happen to others as well but I can't find a solution.
Also, I have tried to limit the reflection to specific tables using the "only" parameter in the metadata.reflect function, and this is the error I get:
sqlalchemy.exc.InvalidRequestError: Could not reflect: requested table(s) not available in mssql+pyodbc://{connection_string}: (users)
I've fixed it. The reflect() method of the SQLAlchemy class has a parameter named 'schema'. Setting this parameter, to "dbo" in my case, solved it.
I am using Flask-SQLAlchemy, which does not have the said parameter in its reflect() method. You can follow this post to gain access to that parameter and others, such as 'only'.
This error occurs when reflect is called without the schema name provided. For example, this will cause the error to happen:
metadata.reflect(only = [tableName])
It needs to be updated to use the schema of the table you are trying to reflect over like this:
metadata.reflect(schema=schemaName, only = [tableName])
You have to set schema='dbo' in parameter for reflect.
db.Model.metadata.reflect(bind=engine, schema='dbo', only=['User'])
and then create model of your table:
class User(db.Model):
__table__ = Base.metadata.tables['dbo.User']
and to access data from that table:

How to get a stored proc to reference a DB from outside its current execution scope

I have 2 DB's, Building and Contact, and a stored proc that executes from the Building DB, building_sp.
building_sp needs to update a table, TblContact, within Contact, and they way I have been referencing it is by
[Contact].dbo.[TblContact]
Since the Contact table can be named arbitrarily, I need to remove this dependency.
The options NOT available to me are
Moving the stored proc logic to code (ie a .NET controller, where the Contact DB name could be set in a web service config file).
Storing the Contact DB name in a meta table/row in the Building DB.
Pass in the a string variable containing the Contact DB name into the building_sp.
Any suggestions or help on this will be appreciated, even just rough ideas or partial answers. Thanks.
I would choose option1: having 2 DataAccess components, one for Building, one for Contact and let a .NET component (controller) to invoke operation on DALs within a transaction (see TransactionScope class).
Why?
Later, you might decide to move those 2 databases on different
machines
Avoid low coupling
Later you might have a third DB invoked, so you have 2 pass 2 DB names or to access many DBs from your SP
You might need to call other services (e.g. sending a mail) and it is more natural to do this kind of operations in .NET
Respect open/close principle: if contact update logic changes, there will be no need to touch Building logic, so less impact, less time involved in testing, lower chances to produce regressions
I let the others to add other reasons here...
I ended up storing the Contact DB name in a web.config app setting
<configuration>
…
<appSettings>
…
<add key="ContactDBName" value="ContactDataBase"/>
</appSettings>
…
</configuration>
I then read this into a global static string from Application_Start()
public class WebApiApplication : System.Web.HttpApplication
{
public static string ContactDBName;
protected void Application_Start()
{
...
ReadContactDBNameFromConfig();
}
protected void ReadContactDBNameFromConfig()
{
System.Configuration.Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/WebServiceName");
System.Configuration.KeyValueConfigurationElement contactDBNameElement = rootWebConfig.AppSettings.Settings["ContactDBName"];
ContactDBName = contactDBNameElement.Value;
}
}
I also stored the stored procedure into a string, using the "place holder" literal "{0}" for the DB name.
public static string BUILDING_SP =
#"BEGIN TRANSACTION
...
UPDATE [{0}].[dbo].[TblContact]
SET param1 = #Param1,
param2 = #Param2,
...
WHERE record_id = #RecordID
...
COMMIT";
I then use String.Format to set the place holder with the DB name
string sql = String.Format(BUILDING_SP, WebApiApplication.ContactDBName);
This string is then executed via a SqlCommand object.

Adding a row to a table from the properties of a class

I have a class that represents the table of a db-row. Its properties are the columns of the table. I add a new row to the table with the following code:
Public Sub AddRow(oTestRow As TestRow)
Dim sql As String
With oTestRow
sql = String.Format("INSERT INTO TestTable " &
"(ArtNr, ArtName, ArtName2, IsVal, CLenght) " &
"Values ('{0}', '{1}', '{2}', {3}, {4})",
.ArtNr, .ArtName, .ArtName2, .IsVal, .CLenght)
End With
Using oConn As New OleDbConnection(m_ConnString)
oConn.Open()
Using oInsertCmd As New OleDbCommand(sql, oConn)
oInsertCmd.ExecuteNonQuery()
End Using
End Using
End Sub
That is just an example, but my classes have around 30-40 properties and this brings a very large and complex sql string.
Creating, editing or maintaining these sql strings for many classes could generate errors.
I am wondering if any compact way or method exists in order to add the whole object's istance (the properties of course) to the table "TestTable" without writing such a large sql string.
I created the TestRow in the way that its properties are exactly the columns of the table "TestTable" (with the same name). But I did not found in the ADO.NET anything that could be used.
If changing DB system is an option, you may wanna take a look at some document based no sql solution like MongoDB, CouchDB or especially for .Net RavenDB, db4o or Eloquera.
Here is a list of some of them.
for starters anything with inline queries is a bad practice (unless the need demands for e.g. you have tables defined in the db, and dont have access to the db to deploy procedures)
you have few options - for e.g. instead of handwriting the classes , use Entitiy framework a better alternative to Linq2Sql
if you want to stick with the tags in this question I would design this making the most of OO concepts. (this is a rough sketch, but I hope this helps)
public class dbObject
protected <type> ID --- This is important. if this has value, commit will assume update, otherwise an update will be performed
public property DBTableName // set the table name
public property CommitStoredprocedure // the procedure on the database that can do commit work
public property SelectStoredProcedure // the procedure used to retrieve the i
public dbObject construcor (connection string or dbcontext etc)
set dbConnection here
end constructor
public method commit
reflect on this.properties available and prepare your commit string.
if you are using storedproc ensure that you prepare named parameters and that the stored proc is defined with the same property names as your class property names. also ensure that storedproc will update if there is an ID value or insert and return a ID when the id value is not available
Create ADO.net command and execute. (this is said easy here but you need to perfect this method)
End method
end class
public class employee inherits dbObject
// employee properties here
public string name;
end employee
public class another inherits dbObject
//another properties
public bool isValid;
end department
usage:
employee e = new employee;
e.name = "John Smith";
e.commit();
console.WriteLine(e.id); // will be the id set by the commit method from the db
If you make baseclass correct (well tested) here, this is automated and you shouldnt see errors.
you will need to extend the base class to Retrieve records from the db based on an id (if you want to instantiate objects from db)

Entity Framework CTP5 - How to Call Stored Procedure?

This may be a simple answer, but i can't see how to execute a stored procedure with EF CTP5.
In Entity Framework 4.0, we did this:
ExecuteFunction("ContainerName.StoredProcName", new ObjectParameter("Id", id)).
Which is a method on the ObjectContext.
But DbContext has no such method.
How do we call a stored proc? Is it not supported in EF CTP5?
EDIT:
I found this thread, which states you need to do this:
var people = context.People.SqlQuery("EXECUTE [dbo].[GetAllPeople]");
This raises some concerns:
1) You are now calling a stored prodedure on the set, not the context. Stored procedures should be available context-wide, not tied to a particular entity set. Just like how they are under the "Database" in SQL Server, and not under the "Table".
2) What about complex types? I previously had a complex type being returned from a stored procedure. But now, it looks as though you have to map directly to an entity? That doesn't make any sense. I have many stored procs that return a type not directly represented by an ObjectSet/DBSet, which i can't see how i can pull over.
Hope someone can clear this up for me, because from what i understand so far, i won't be able to upgrade to CTP5.
You can execute database-wide sql statements like this
using(var context = new MyContext())
{
// custum sql statement
var c = context.Database.SqlQuery<int>("SELECT COUNT(*) FROM Employees");
// returned entity type doesn't have to be represented by ObjectSet/DBSet
var e = context.Database.SqlQuery<Employee>("SELECT * FROM Employees");
// stored procedure
var q = context.Database.SqlQuery<Employee>("GetEmployees");
}

Resources