DatabaseGeneratedOption doesn't work in Dapper.FastCRUD - c#

I setup my mapping like this:
[Table("Opportunity")]
public partial class Opportunity
{
// Other columns
...
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long OPPORTUNITY_ID { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long? OPPORTUNITY_VALUE { get; set; }
// Other columns
...
}
My unit test is setup like this:
Opportunity opp = new Opportunity
{
DATE_CREATED_UTC = DateTime.UtcNow,
OWNER_USER_ID = TestConstants.USER_ID,
OPPORTUNITY_NAME = "unitTest-Opportunity",
PROBABILITY = 50,
BID_CURRENCY = "USD",
BID_AMOUNT = 6000,
BID_TYPE = "Fixed Bid",
OPPORTUNITY_STATE = "OPEN",
OPPORTUNITY_DETAILS = "UNIT TEST OPPORUNITY DETAIL",
VISIBLE_TO = "EVERYONE"
};
OppService.Add(opp);
Opportunity fromDB = OppService.Get(opp.OPPORTUNITY_ID);
OppService.Update(fromDB);
The last line would crash with the error: The column "OPPORTUNITY_VALUE" cannot be modified because it is either a computed column or is the result of a UNION operator.
What am I doing wrong? I am not modifying that column value at all. Here is the full error stack:
Result StackTrace:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Dapper.SqlMapper.ExecuteCommand(IDbConnection cnn, CommandDefinition& command, Action`2 paramReader) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 3397
at Dapper.SqlMapper.ExecuteImpl(IDbConnection cnn, CommandDefinition& command) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 1346
at Dapper.FastCrud.SqlStatements.GenericSqlStatements`1.UpdateById(IDbConnection connection, TEntity keyEntity, ISqlStatementOptionsGetter statementOptions)
at Dapper.FastCrud.DapperExtensions.Update[TEntity](IDbConnection connection, TEntity entityToUpdate, Action`1 statementOptions)
at MyProject.Data.Repository`1.Update(T entity) in C:\MyFolder\Core\MyProject.Data\Repository.cs:line 80
at MyProject.Service.Base.ModelService`1.Update(T entity) in C:\MyFolder\Core\MyProject.Service\Base\ModelService.cs:line 38
at MyProject.Service.Base.InstanceEntityService`2.Update(T entity) in C:\MyFolder\Core\MyProject.Service\Base\InstanceEntityService.cs:line 72
at MyProject.Service.OpportunityService.Update(Opportunity entity) in C:\MyFolder\Core\MyProject.Service\OpportunityService.cs:line 21
at MyProject.Test.Service.OpportunityServiceTests.OpportunitiesCRUDTest() in C:\MyFolder\Test\Core\Service\OpportunityServiceTest.cs:line 22
Result Message: System.Data.SqlClient.SqlException : The column "OPPORTUNITY_VALUE" cannot be modified because it is either a computed column or is the result of a UNION operator.
CREATE statement for the table Opportunity:
CREATE TABLE [dbo].[Opportunity](
[OPPORTUNITY_ID] [bigint] IDENTITY(1,1) NOT NULL,
// Other columns
[BID_CURRENCY] [nvarchar](20) NULL,
[BID_AMOUNT] [bigint] NULL,
[BID_TYPE] [varchar](20) NULL,
[BID_DURATION] [int] NULL,
[OPPORTUNITY_VALUE] AS (case when [BID_TYPE]='Fixed Bid' AND [BID_AMOUNT] IS NOT NULL then [BID_AMOUNT] when [BID_TYPE]='Fixed Bid' AND [BID_AMOUNT] IS NULL then NULL when [BID_AMOUNT] IS NOT NULL AND [BID_DURATION] IS NOT NULL then [BID_AMOUNT]*[BID_DURATION] when [BID_DURATION] IS NULL then [BID_AMOUNT] end) PERSISTED,
[SEQUENCE_ID] [int] NULL,
[DELETED] [bit] NOT NULL,
[DELETED_DATE_UTC] [datetime] NULL,
[DELETED_USER_ID] [int] NULL,
CONSTRAINT [PK_OPPORTUNITY] PRIMARY KEY CLUSTERED
(
[INSTANCE_ID] ASC,
[OPPORTUNITY_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

Turns out the current version of Dapper.FastCrud doesn't properly support computed columns. Please watch for a resolution to this ticket.
UPDATE: The problem was fixed in 2.3.0.

Related

Getting error for HierarchyId while fetching the data from another server and inserting it into my server c#

Error is
The type of column 'MemberHId' is not supported. The type is 'SqlHierarchyId'.
In both the server the datatype is same "HierarchyId".
I am just using the ADO.Net.
The assembly is Microsoft.SqlServer.ManagedDTS version- 13.0.0.0
We are using Azure Sql.
Tried with different versions of sql assemblies
DataTable dt = new DataTable();
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Description", typeof(string));
dt.Columns.Add("NodeId", typeof(int));
dt.Columns.Add("MemberHId", typeof(SqlHierarchyId));
dt.Columns.Add("Level", typeof(int));
//Getting the data from serverAPI which is returning the data in the columns without null records.
dt=apicall();
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = spName;
cmd.Parameters.AddWithValue("#MemberH", dt);
cmd.CommandTimeout = 0;
cmd.Connection.Open();
cmd.ExecuteNonQuery();// Its failing here
My Sp consists of table type param #MemberHType and the procedure returns rows with these columns:
Name | Type
------------+----------
Code | varchar
Description | varchar
NodeID | smallint
MemberHId | hierarchyid
Level | smallint
This is the procedure:
alter PROCEDURE [dbo].[InsertHierarchyData]
(
#MemberHType MemberH READONLY
)
AS
truncate table test
BEGIN TRY
insert into test values ('start select')
--create table test (errormessage varchar(1000))
IF EXISTS (SELECT TOP 1 1 FROM #MemberHType)
BEGIN
insert into test values ('Inside first Insert start')
INSERT INTO HierarchyStaging
(
Code
,[Description]
,NodeID
,MemberhHId
,[Level]
)
SELECT
Code
,[Description]
,NodeId
,MemberhHId
,[Level]
FROM #MemberHType
insert into test values ('Inside first Insert end')
END
END TRY
BEGIN CATCH
SELECT #comment = ERROR_MESSAGE()
,#Status = 'Error'
SET #comment = CONVERT(NVARCHAR(3000),#Comment) + ' Error Severity: ' + CAST(ERROR_SEVERITY() AS varchar(25)) + ' Error state: 30'
GOTO ErrorHandler
END CATCH
The Column in c# is SqlHierarchyId.
Stack-trace:
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
If I understand the documentation correctly, you can't use SqlHierarchyId as the data type of a DataColumn.
It doesn't appear in the System.Data.SqlTypes Namespace, and it also doesn't appear in the SQL Server Data Type Mappings table, which means there's no documented built in conversion between SQL Server's HierarchyId and a built in type in the .Net framework. (of course, undocumented features have been known to exist in SQL Server, but I wouldn't recommend relying on that).
What you can do, however, is to convert the HierarchyId to nvarchar using a simple cast in T-SQL when you read it into your c# application (which internally is calling the ToString() method):
CAST(MemberhHId AS nvarchar(4000)) as MemberHId
and convert it back using cast when you insert the data (which internally is calling the Parse() method):
CAST(MemberHId AS hierarchyid)

Convert to Int Error without using int

I have a C# code which throws me a SQLException with message Error Converting data type varchar to int. Funny thing is I dont have any conversion or INT variables in my code. My stored procedure works fine on its own via SSMS.
Here is the C# bit
string[] envData = new string[4];
string dbCon = "";
dbCon = "Database=" + "TestData";
dbCon = dbCon + ";Server=" + "DEV";
dbCon = dbCon + ";Trusted_Connection=Yes;";
using (SqlConnection Con = new SqlConnection(dbCon))
{
Con.Open();
//using (SqlTransaction tr = Con.BeginTransaction("GetEnvironmentInfo"))
//{
string spEnvironmentInfo = #"ELog.GetEnvironmentInfo";
SqlCommand cmd = new SqlCommand(spEnvironmentInfo, Con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#oElogBaseDir", DbType.String));
cmd.Parameters["#oElogBaseDir"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogFinancialMonthDir", DbType.String));
cmd.Parameters["#oElogFinancialMonthDir"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogFinancialYear", DbType.String));
cmd.Parameters["#oElogFinancialYear"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#oElogEmailAccount", DbType.String));
cmd.Parameters["#oElogEmailAccount"].Direction = ParameterDirection.Output;
try
{
cmd.ExecuteNonQuery();
envData[0] = cmd.Parameters["#oElogBaseDir"].Value.ToString();
envData[1] = cmd.Parameters["#oElogFinancialMonthDir"].Value.ToString();
envData[2] = cmd.Parameters["#oElogFinancialYear"].Value.ToString();
envData[3] = cmd.Parameters["#oElogEmailAccount"].Value.ToString();
//tr.Commit();
}
catch (System.Exception ex)
{
//tr.Rollback("GetEnvironmentInfo");
throw ex;
//return null;
}
//}
}
Response.Write(envData[0].ToString());
Response.Write(envData[1].ToString());
Response.Write(envData[2].ToString());
Response.Write(envData[3].ToString());
and here is the sql part
ALTER PROCEDURE [ELog].[GetEnvironmentInfo]
#oELogBaseDir VARCHAR(MAX) OUTPUT,
#oELogFinancialMonthDir VARCHAR(MAX) OUTPUT,
#oELogFinancialYear VARCHAR(MAX) OUTPUT,
#oElogEmailAccount VARCHAR(MAX) OUTPUT
AS
BEGIN
SELECT
#oELogBaseDir = e.ELogBaseDir,
#oELogFinancialMonthDir = e.ELogFinancialMonthDir,
#oELogFinancialYear = e.ELogFinancialYear,
#oElogEmailAccount = e.ElogEmailAccount
FROM SSISMeta.Environment e
WHERE e.SQLServerInstance = ##SERVERNAME
END
Here is the stack trace
[SqlException (0x80131904): Error converting data type varchar to int.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +2442126
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +5736904
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +628
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +3731
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +225
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest) +2026
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +375
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) +337
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +280
WebTest_Replacement_OutlookVB.Test_Home.btnReadEmail_Click(Object sender, EventArgs e) in \\LocalDev\Random\WebTest_Replacement_OutlookVB\Test_Home.aspx.cs:70
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +9692746
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +108
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +12
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +15
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +35
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3562
Table schema
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
GO
CREATE TABLE [SSISMeta].[Environment] (
[SK_EnvironmentID] [smallint] IDENTITY(1, 1) NOT NULL,
[IsProduction] [bit] NOT NULL,
[SQLServerInstance] [varchar](100) COLLATE Latin1_General_CI_AS NOT NULL,
[BaseDirPath] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[CreatedTimeStamp] [datetime] NOT NULL,
[LastUpdatedTimeStamp] [datetime] NOT NULL,
[ModifiedBYUser] [varchar](100) COLLATE Latin1_General_CI_AS NOT NULL,
[SharedBaseDir] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[SharedT2ODir] [varchar](4000) COLLATE Latin1_General_CI_AS NULL,
[ELogBaseDir] [varchar](4000) COLLATE Latin1_General_CI_AS NOT NULL,
[ELogFinancialMonthDir] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
[ELogFinancialYear] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
[ElogEmailAccount] [varchar](250) COLLATE Latin1_General_CI_AS NOT NULL,
CONSTRAINT [PK_Environment]
PRIMARY KEY
CLUSTERED
([SK_EnvironmentID])
ON [SSISMeta_Data_Fg]
) ON [SSISMeta_Data_Fg]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_CreatedTimestamp]
DEFAULT (getdate()) FOR [CreatedTimeStamp]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_LastUpdatedTimestamp]
DEFAULT (getdate()) FOR [LastUpdatedTimeStamp]
GO
ALTER TABLE [SSISMeta].[Environment]
ADD
CONSTRAINT [DF_Environment_ModifiedByUser]
DEFAULT (suser_sname()) FOR [ModifiedBYUser]
GO
ALTER TABLE [SSISMeta].[Environment] SET (LOCK_ESCALATION = TABLE)
GO
I knew it was going to be something silly, I need to use SqlDbType not DbType.
Works fine now

how to use c# variables in sql commands

This is what I want to use;
string insertQuery = #"insert into userinfo (UserName, FirstName, LastName,
E-mail, Password, Country)
values ( '" + uname + "', '" + fname +
"','" + lname + "', '" + email + "')";
where every one of the variables in between the + are string variables with values in them. but when I run this command, I get some incorrect syntax error.
This is the new error i get;
errorSystem.Data.SqlClient.SqlException (0x80131904): String or binary
data would be truncated. The statement has been terminated. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj, Boolean& dataReady) at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean
async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader
ds) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String
method, TaskCompletionSource1 completion, Int32 timeout, Task& task,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1
completion, String methodName, Boolean sendToPipe, Int32 timeout,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at
Registration.RegistrationPage.Button1_Click1(Object sender, EventArgs
e) in c:\Users\kristhnen.jagambrum\Documents\Visual Studio
2012\Projects\Registration\Registration\RegistrationPage.aspx.cs:line
50 ClientConnectionId:6d959e49-5b62-43be-b202-76f7eb1fbd2c
It's very good that you asked - the code that you show is a perfect illustration of two security issues in a single line:
The table structure is an illustration of what lets hackers steal user passwords.
The C# code is what makes SQL injection attacks possible.
Fixing the first problem is hard: you need to learn about password hashing and how to store user info in DB. Here is a Q&A that will help: Best way to store passwords in DB
The second problem is easier - all you need is replacing the injected values with parameter names, and then adding the values for each parameter name:
... // Create SQL command, then set its text
command.CommandTest = #"INSERT INTO userinfo (
UserName, FirstName, LastName, E-mail, Password_hash, Password_salt, Country
) VALUES ( #uname, #fname, #lname, #email, #pwd_hash, #pwd_salt, #country)";
// Bind the parameters
command.Parameters.Add(new SqlParameter("#uname", uname));
command.Parameters.Add(new SqlParameter("#fname", fname));
... // ...and so on
command.ExecuteNonQuery();
The answer is you don't, because it is a bad idea. You should be using SQlCommand instead
Check This out,and there are plenty of examples of how to use it. Appending variables in the way you doing is considered to be the mistake number 3 in the list of 25 most dangerous programming mistakes.
Try something like this, and not use direct parameter in sql command
public const string InsertStmtUsersTable = "insert into userinfo (UserName, FirstName, LastName,
[E-mail], Password, Country) values (#UserName, #FirstName, #LastName,
#[E-mail], #Password, #Country) "
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(InsertStmtUsersTable, conn))
{
command.CommandType = CommandType.Text;
command.Parameters.Add(new SqlParameter("username", userNameString));
command.Parameters.Add(new SqlParameter("FirstName", FirstNameString));
// Rest of your Parameters here
command.ExecuteNonQuery();
}
}

C# Entity Framework Commit Error

I have a weird error when trying to call .SaveChanges() in Entity Framework.
I'm trying to save an Order like this
public void SaveOrder(UserDTO user, ArticleDTO article, PriceDTO price, decimal amount)
{
//Get the order with type cart. If no order exist create a new order with type cart.
var order = _orderRepository.GetCartOrderForCustomer(user.Customer.CustomerREFID);
if (order == null)
{
order = new Order()
{
CustomerREFID = user.Customer.CustomerREFID,
CreateDate = DateTime.Now,
OrderType = OrderType.Cart
};
_orderRepository.Add(order);
_orderRepository.UnitOfWork.Commit();
}
}
Sure its working fine when I'm only calling this method. But when I'm calling another method before this method then I get errors.
The before method just fetch articles and prices.
public IEnumerable<Article> GetArticlesByCategory(int categorySection, int headCategory, string customerREFID)
{
var currentUnitOfWork = this.UnitOfWork as MainBCUnitOfWork;
//Linq query without keys.
var result = (from a in currentUnitOfWork.Articles
join cat in currentUnitOfWork.Categories on a.CategoryID equals cat.CategoryID
join cf in currentUnitOfWork.CategoryReferences on cat.ID equals cf.CategoryID
join c in currentUnitOfWork.Customers on a.Lagstalle equals c.LagStalle
where cf.RefID == categorySection && cat.HuvudKat == headCategory && c.CustomerREFID == customerREFID
select a).ToList();
var artnumbers = result.Select(a => a.Number).ToList();
var prices = currentUnitOfWork.Prices.Where(p => artnumbers.Contains(p.ArtNr) && p.FtgNr == customerREFID).ToList();
Parallel.ForEach(result, a =>
{
a.Prices = prices.Where(p => p.ArtNr == a.Number).ToList();
});
return result.ToList();
}
So when calling SaveOrder I get this error :
{System.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_dbo.PriceArticles'. Cannot insert duplicate key in object 'dbo.PriceArticles'. The duplicate key value is (6653, 1).
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary2 identifierValues, List1 generatedValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
ClientConnectionId:dfc62e28-3751-4a54-89f4-5fa8195cab2a}
This table and get has nothing to do with Order table ? Why does Entity Framework commit other tables when I only add a new Order ?
How do I work around this ?

EF 4.1 Code First problem with parent child and Inheritance Mapping

I have run into some problems with Inheritance Mapping, I can't get it to map correct to the base class, and get an Invalid column on all the fields in the base class (Elements)
The project wos working before we upgraded from CTP5 to 4.1 and where using the .IsIndependent()
My code look like this:
Table structure:
CREATE TABLE [dbo].[elements](
[elementID] [uniqueidentifier] NOT NULL,
[elementElementID] [uniqueidentifier] NULL,
[name] [nvarchar](50) NOT NULL,
[solutionID] [int] NOT NULL,
[elementTypeID] [int] NOT NULL,
[dateCreate] [datetime] NOT NULL,
[dateChange] [datetime] NOT NULL,
[placeholderNumber] [int] NULL
)
CREATE TABLE [dbo].[elementRoots](
[elementID] [uniqueidentifier] NOT NULL,
[allowsiteCounts] [int] NOT NULL
)
CREATE TABLE [dbo].[elementSites](
[elementID] [uniqueidentifier] NOT NULL,
[languageCode] [nvarchar](5) NOT NULL
)
CREATE TABLE [dbo].[elementPages](
[elementID] [uniqueidentifier] NOT NULL,
[elementMasterID] [uniqueidentifier] NULL,
[title] [nvarchar](50) NOT NULL,
[desciption] [nvarchar](255) NULL,
[path] [nvarchar](512) NULL,
)
Mapping;
public DbSet<Element> Elements { get; set; }
public DbSet<ElementRoot> ElementRoots { get; set; }
public DbSet<ElementSite> ElementSites { get; set; }
public DbSet<ElementPage> ElementPages { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Element>().HasKey(x => x.elementId);
modelBuilder.Entity<Element>()
.HasOptional(s => s.Parent)
.WithMany(c => c.Children)
.HasForeignKey(s => s.elementElementId);
modelBuilder.Entity<Element>().ToTable("elements");
modelBuilder.Entity<ElementRoot>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("elementRoots");
});
modelBuilder.Entity<ElementSite>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("elementSites");
});
modelBuilder.Entity<ElementPage>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("elementPages");
});
}
Error message i recive:
Invalid column name 'solutionID'.
Invalid column name 'name'.
Invalid column name 'solutionID'.
Invalid column name 'elementTypeID'.
Invalid column name 'dateCreate'.
Invalid column name 'dateChange'.
Invalid column name 'elementElementId'.
Invalid column name 'placeholderNumber'.
Invalid column name 'solutionID'.
Invalid column name 'name'.
Invalid column name 'solutionID'.
Invalid column name 'elementTypeID'.
Invalid column name 'dateCreate'.
Invalid column name 'dateChange'.
Invalid column name 'elementElementId'.
Invalid column name 'placeholderNumber'.
Invalid column name 'solutionID'.
Invalid column name 'name'.
Invalid column name 'solutionID'.
Invalid column name 'elementTypeID'.
Invalid column name 'dateCreate'.
Invalid column name 'dateChange'.
Invalid column name 'elementElementId'.
Invalid column name 'placeholderNumber'.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +2030802
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +5009584
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() +234
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2275
System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33
System.Data.SqlClient.SqlDataReader.get_MetaData() +86
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +311
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +987
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +443
Your mapping is completely wrong. Your database has separate table for each entity (including the base entity type Elements). It means that you have to use Table-per-Type (TPT) mapping but your code is using Table-Per-Concrete Type (TPC) mapping. TPC requires that table for base type does not exists and instead tables for all derived entities have all base type's columns. That is the reason why you cat that exception. Remove m.MapInheritedProperties(); from all your child mappings.

Categories

Resources