EF 4.1 Code First problem with parent child and Inheritance Mapping - c#

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.

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

DatabaseGeneratedOption doesn't work in Dapper.FastCRUD

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.

How to get Guid from SqlDataReader uniqueidentifier

SQL Server 2008 (version 10.50.2550).
I have a select query to return a single column of type uniqueidentifier.
I want to get this into a C# variable of type Guid.
All of the following methods result in exceptions.
reader is of type SqlDataReader.
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
Guid guid = reader.GetGuid(reader.GetOrdinal("integ_schemehistoryId")); //1
Guid guid = Guid.Parse((string)reader["integ_schemehistoryId"]); //2
Guid guid = (Guid)reader["integ_schemehistoryId"]; //3
Guid guid = new Guid((string)reader["integ_schemehistoryId"]); //4
Guid guid = Guid.Parse(reader["integ_schemehistoryId"].ToString()); //5
}
}
Error for 1:
System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
Error for 2:
System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'.
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
Error for 3:
System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
Error for 4:
System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'.
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
Error for 5:
System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
There is something wrong either with your data or your SQL. The first and third approaches should work - personally I'd use the first form, as it's the clearest in my view.
But look at the stack trace:
...
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at System.Data.SqlClient.SqlDataReader.Read()
at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
Note that it's the Read() call which is failing, not GetGuid or the indexer.
My guess is that your property is being fetched several times, and sometimes it works - which is why you were getting a cast exception in your second approach - but for some rows, it fails due to some problem with the data or the SQL. As we've no idea where your data is coming from, we can't help you beyond that diagnosis, but that's where you should look next.
As the other answers suggest, you should try:
Guid guid = Guid.Parse(reader["integ_schemehistoryId"].ToString())
You might also want to check your stored procedures and your table, there may be something wrong there.
That error is being generated from SQL. In other words there something wrong with you SQL command text. Not your c# code.
Have you tried:
Guid guid = new Guid((string)reader["integ_schemehistoryId"]);
Try by using Guid.Parse method
Guid guid = return Guid.Parse((string)reader["integ_schemehistoryId"]);
In Oracle database:
"ID" RAW(16) DEFAULT SYS_GUID() NOT NULL ENABLE,
This code worked for me:
using (IDataReader dr = ... )
{
while (dr.Read())
{
var Id = new Guid();
if (!(dr["ID"] is DBNull)){
Id = new Guid((byte[])dr.GetValue(dr.GetOrdinal("ID")));
}
}
dr.Close();
}
object val = reader[0];
Guid g;
if ( Guid.TryParse(val, out g) )
{
return g;
}
else
{
Trace.WriteLine("Error: " + g == null ? string.Empty : g.ToString());
}

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 ?

Categories

Resources