I am developing an App using MVC5 and using Entity Framework Code first Approach for development. I have an ID column in Employee.cs Model class which auto increments as the Record is Inserted. I want to know How can I add another Column in my table with varchar type which will Look something Like this. EMP233 where 233 i an ID Generated by Identiy Column.
Note:
I know how to do this task using SQL Server but I am curious to Know How it Can be done using EF Code first Approach.
Many people will Suggest me to get the latest max ID from db, Increment it and add it to the object something Like
int EmpMaxID = db.Employees.OrderByDescending(u => u.ID).FirstOrDefault();
employee.VarcharID = "EMP" + EmpMaxID;
This Approach is not the Best because lets suppose if the user add a record and system generates its ID as 234 and Moment after he deletes it. Then next time in this case system will return Max ID as 233 i.e. EmpMaxID = 233 but the ID Generated by System is going to be 235. So what we will get in return is a Record with ID = 235 AND EmpID = "EMP233" Which is wrong. I hope you got my Point.
Here is what I have tried but It didn't Work. IN THE MODELS I wrote something like this
public int ID { get; set; } // Unique numeric ID for each Employee
public string strEmpID // A varchar ID
{
get { return strEmpID}
set { strEmpID= "EMP" + ID; } // ID is Auto Generated
}
This Doesn't Work. Please help me completing this Task. Thanks
When you save this record for the first time, get the Id, update the strEmpID property as well.
var emp = new Employee { Name="Scott" };
db.Employees.Add(emp);
db.SaveChanges();
if (String.IsNullOrEmpty(emp.strEmpID))
{
e.strEmpID = "EMP" + e.Id;
db.Entry(e).State=EntityState.Modified;
db.SaveChanges();
}
The only safe way is to add the record and then get the id and update the record.
using (var context = new MyContext())
{
context.MyEntities.AddObject(newEmployee);
context.SaveChanges();
int id = newEmployee.Id; // Your Identity column ID
newEmployee.streEmpId = "EMP" + id;
context.Entry(newEmployee).State = EntityState.Modified;
context.SaveChanges();
}
I'm trying to recieve data from an database table and my sql query also selects a column from another table that i would like to return aswell
while (dr.Read())
{
Inlagg comentsar = new Inlagg
{
names = (int)dr["name"],
dates = (DateTime)dr["Date"]
//get column value from the other table not the Inlagg table here pobbisble?
};
//This gets the column value from the other table but i dont know how to return it
string test = (string)dr["test"];
comen.Add(comentsar);
}
return comen;
How can i return a result that includes columns both columns from different tables? Side note: I have a column that i dont need to recieve here, altough the column is an int and i'm trying to recieve an string, is there any way to cast the column to an string? Any help or input highly appreciated, thanks!
EDIT: "Solved" it by simply creating a new class with the values i wanted which included columnvalues from different tables
Inside of your reader, your missing the following:
if(reader["Column"] != DBNull.Value)
model.Name = reader["Column"].ToString();
Your query for your SQL should correctly join the multiple tables, then in the returned result set you would have a column name to return by. You call the reader["..."] to access the value for said column.
As you notice the model class calls a name of a property.
The model is important as it represents your data, but to access through the reader you simply add another property.
That is because the column is null, so you can't cast a ToString() that is why the error occurs. You could attempt to also do:
int? example = reader["Column"] as int?;
Extend your class:
public class Inlagg{
...
addMyString(String myString){
this.myString = myString;
}
getMyString(){
return this.myString;
}
}
I have following scenario...
Massive Micro-ORM
.NET framework 4.0
SQL Server 2008R2
Model:
public class sUser : DynamicModel
{
public sUser() : base(Model.strConnection, "Users", "UserId") { }
}
public class Test
{
public void UpdateUser(string user)
{
dynamic User = GetUser(user);
//Dynamically generated User object has many columns
// I Update following fields...
User.Address1 = "123 Main Street";
User.Address2 = "Suite# 456";
User.CityName = "Princeton";
User.State = "NJ";
User.Zipcode = "08540";
//And update some more fields in Users object
//I could do this...
//var upd = new { Address1 = "123 Main Street", Address2 = "Suite# 456", ...};
//User.Update(upd, User.UserID);
//But would like to pass entire object, so I do not have to form all updated name/value in the update statement
User.Update(User, User.UserID);
//But Users table has a column with IDENTITY SEED,
//And if I pass entire object for update it errors out
//Cannot update identity column 'RefNo'
}
public dynamic GetUser(string userName)
{
dynamic table = new sUser();
var objUser = table.First(UserName: userName);
return objUser;
}
}
Users table has a column RefNo with IDENTITY SEED=1, and when I update entire User object, it errors out Cannot update identity column 'RefNo'. I would like to pass entire object for update rather than forming long update statement.
How can I handle this?
Thanks.
If your Users table has a column RefNo with IDENTITY SEED = 1, then that would imply it is your primary key. In you sUser class, you are calling the base constructor with:
base(Model.strConnection, "Users", "UserId")
This call is telling Massive that the primary key column is UserId - what happens if you instead pass it RefNo?
Edit:
I think I see the problem you are having: Massive will generate an update statement including all the properties of your object, including RefNo. Because the database is taking care of this column (via IDENTITY SEED), you can't modify or set this value.
What I would suggest instead is taking advantage of the fact that User is returned as an ExpandoObject. What you could do is this:
((IDictionary<string, object>)User).Remove("RefNo");
User.Update(User, User.UserID);
What this will do is remove the RefNo property from the object, meaning that it won't be included in the update statement that gets created, which should in turn result in the Update call succedding.
Modify Massive.cs
- Add following under DynamicModel class
private string IdentityColumn { get; set; }
private string GetIdentityColumn()
{
return (string)Scalar("SELECT C.name AS IdentityColumn FROM sys.columns C Inner Join sys.tables T ON T.object_id = C.object_id WHERE C.is_identity = 1 And T.name = '" + TableName + "'");
}
And under CreateUpdateCommand method add following...
IdentityColumn = GetIdentityColumn();
And under foreach loop modify if statement to following...
if (!item.Key.Equals(PrimaryKeyField, StringComparison.OrdinalIgnoreCase) && item.Value != null && item.Key != IdentityColumn)
Above change into Massive library would allow us to update model with identity column. Limitation: Works for Table with one IDENTITY column.
I'm using a dataset. I have a table Adapter called PackageTableAdapter, which contains a method called InsertPackage.
INSERT INTO [dbo].[Packages] ([UserID], [Name]) VALUES (#UserID, #Name)
//Return the PackageID value for the newly created record...
SELECT SCOPE_IDENTITY()
This table adapter is being used by a middle tier class, with the below code:
private PackagesTableAdapter _packagesTableAdapter = null;
protected PackagesTableAdapter Adapter
{
get
{
if (_packagesTableAdapter == null)
_packagesTableAdapter = new PackagesTableAdapter();
return _packagesTableAdapter;
}
}
public bool AddPackage(string PackageName)
{
// Create a new PackageRow instance
Album.PackagesDataTable packages = new AlbumCongo.PackagesDataTable();
Album.PackagesRow package = packages.NewPackagesRow();
// Add the new package
package.Name = PackageName;
packages.AddPackagesRow(package);
int rowsAffected = Adapter.Update(packages);
// Return true if precisely one row was inserted,
// otherwise false
return rowsAffected == 1;
}
How do I capture the primary key of the newly created package (the one that's supposed to returned by the SELECT SCOPE_IDENTITY() statement)?
EDIT
Instead of returning a bool value, I'd like to return a custom object that contains both the bool value and an int representing the ID of the newly created row.
Thanks for helping.
First of all you have to make the return type of the insert method to Scaler. You can also do so by right clicking the properties of your insert Method properties.
Secondly you can get the ID by calling the Adapter method like this:
Int32 ID = Convert.ToInt32(Adapter.Insert(parameters...);
Check the PackageID on the DataRow object AFTER the Adapter.Update call.
I have a C# code which does lot of insert statements in a batch. While executing these statements, I got "String or binary data would be truncated" error and transaction roledback.
To find out the which insert statement caused this, I need to insert one by one in the SQLServer until I hit the error.
Is there clever way to findout which statement and which field caused this issue using exception handling? (SqlException)
In general, there isn't a way to determine which particular statement caused the error. If you're running several, you could watch profiler and look at the last completed statement and see what the statement after that might be, though I have no idea if that approach is feasible for you.
In any event, one of your parameter variables (and the data inside it) is too large for the field it's trying to store data in. Check your parameter sizes against column sizes and the field(s) in question should be evident pretty quickly.
This type of error occurs when the datatype of the SQL Server column has a length which is less than the length of the data entered into the entry form.
this type of error generally occurs when you have to put characters or values more than that you have specified in Database table like in that case: you specify
transaction_status varchar(10)
but you actually trying to store
_transaction_status
which contain 19 characters. that's why you faced this type of error in this code
Generally it is that you are inserting a value that is greater than the maximum allowed value. Ex, data column can only hold up to 200 characters, but you are inserting 201-character string
BEGIN TRY
INSERT INTO YourTable (col1, col2) VALUES (#val1, #val2)
END TRY
BEGIN CATCH
--print or insert into error log or return param or etc...
PRINT '#val1='+ISNULL(CONVERT(varchar,#val1),'')
PRINT '#val2='+ISNULL(CONVERT(varchar,#val2),'')
END CATCH
For SQL 2016 SP2 or higher follow this link
For older versions of SQL do this:
Get the query that is causing the problems (you can also use SQL Profiler if you dont have the source)
Remove all WHERE clauses and other unimportant parts until you are basically just left with the SELECT and FROM parts
Add WHERE 0 = 1 (this will select only table structure)
Add INTO [MyTempTable] just before the FROM clause
You should end up with something like
SELECT
Col1, Col2, ..., [ColN]
INTO [MyTempTable]
FROM
[Tables etc.]
WHERE 0 = 1
This will create a table called MyTempTable in your DB that you can compare to your target table structure i.e. you can compare the columns on both tables to see where they differ. It is a bit of a workaround but it is the quickest method I have found.
It depends on how you are making the Insert Calls. All as one call, or as individual calls within a transaction? If individual calls, then yes (as you iterate through the calls, catch the one that fails). If one large call, then no. SQL is processing the whole statement, so it's out of the hands of the code.
I have created a simple way of finding offending fields by:
Getting the column width of all the columns of a table where we're trying to make this insert/ update. (I'm getting this info directly from the database.)
Comparing the column widths to the width of the values we're trying to insert/ update.
Assumptions/ Limitations:
The column names of the table in the database match with the C# entity fields. For eg: If you have a column like this in database:
You need to have your Entity with the same column name:
public class SomeTable
{
// Other fields
public string SourceData { get; set; }
}
You're inserting/ updating 1 entity at a time. It'll be clearer in the demo code below. (If you're doing bulk inserts/ updates, you might want to either modify it or use some other solution.)
Step 1:
Get the column width of all the columns directly from the database:
// For this, I took help from Microsoft docs website:
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.getschema?view=netframework-4.7.2#System_Data_SqlClient_SqlConnection_GetSchema_System_String_System_String___
private static Dictionary<string, int> GetColumnSizesOfTableFromDatabase(string tableName, string connectionString)
{
var columnSizes = new Dictionary<string, int>();
using (var connection = new SqlConnection(connectionString))
{
// Connect to the database then retrieve the schema information.
connection.Open();
// You can specify the Catalog, Schema, Table Name, Column Name to get the specified column(s).
// You can use four restrictions for Column, so you should create a 4 members array.
String[] columnRestrictions = new String[4];
// For the array, 0-member represents Catalog; 1-member represents Schema;
// 2-member represents Table Name; 3-member represents Column Name.
// Now we specify the Table_Name and Column_Name of the columns what we want to get schema information.
columnRestrictions[2] = tableName;
DataTable allColumnsSchemaTable = connection.GetSchema("Columns", columnRestrictions);
foreach (DataRow row in allColumnsSchemaTable.Rows)
{
var columnName = row.Field<string>("COLUMN_NAME");
//var dataType = row.Field<string>("DATA_TYPE");
var characterMaxLength = row.Field<int?>("CHARACTER_MAXIMUM_LENGTH");
// I'm only capturing columns whose Datatype is "varchar" or "char", i.e. their CHARACTER_MAXIMUM_LENGTH won't be null.
if(characterMaxLength != null)
{
columnSizes.Add(columnName, characterMaxLength.Value);
}
}
connection.Close();
}
return columnSizes;
}
Step 2:
Compare the column widths with the width of the values we're trying to insert/ update:
public static Dictionary<string, string> FindLongBinaryOrStringFields<T>(T entity, string connectionString)
{
var tableName = typeof(T).Name;
Dictionary<string, string> longFields = new Dictionary<string, string>();
var objectProperties = GetProperties(entity);
//var fieldNames = objectProperties.Select(p => p.Name).ToList();
var actualDatabaseColumnSizes = GetColumnSizesOfTableFromDatabase(tableName, connectionString);
foreach (var dbColumn in actualDatabaseColumnSizes)
{
var maxLengthOfThisColumn = dbColumn.Value;
var currentValueOfThisField = objectProperties.Where(f => f.Name == dbColumn.Key).First()?.GetValue(entity, null)?.ToString();
if (!string.IsNullOrEmpty(currentValueOfThisField) && currentValueOfThisField.Length > maxLengthOfThisColumn)
{
longFields.Add(dbColumn.Key, $"'{dbColumn.Key}' column cannot take the value of '{currentValueOfThisField}' because the max length it can take is {maxLengthOfThisColumn}.");
}
}
return longFields;
}
public static List<PropertyInfo> GetProperties<T>(T entity)
{
//The DeclaredOnly flag makes sure you only get properties of the object, not from the classes it derives from.
var properties = entity.GetType()
.GetProperties(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.DeclaredOnly)
.ToList();
return properties;
}
Demo:
Let's say we're trying to insert someTableEntity of SomeTable class that is modeled in our app like so:
public class SomeTable
{
[Key]
public long TicketID { get; set; }
public string SourceData { get; set; }
}
And it's inside our SomeDbContext like so:
public class SomeDbContext : DbContext
{
public DbSet<SomeTable> SomeTables { get; set; }
}
This table in Db has SourceData field as varchar(16) like so:
Now we'll try to insert value that is longer than 16 characters into this field and capture this information:
public void SaveSomeTableEntity()
{
var connectionString = "server=SERVER_NAME;database=DB_NAME;User ID=SOME_ID;Password=SOME_PASSWORD;Connection Timeout=200";
using (var context = new SomeDbContext(connectionString))
{
var someTableEntity = new SomeTable()
{
SourceData = "Blah-Blah-Blah-Blah-Blah-Blah"
};
context.SomeTables.Add(someTableEntity);
try
{
context.SaveChanges();
}
catch (Exception ex)
{
if (ex.GetBaseException().Message == "String or binary data would be truncated.\r\nThe statement has been terminated.")
{
var badFieldsReport = "";
List<string> badFields = new List<string>();
// YOU GOT YOUR FIELDS RIGHT HERE:
var longFields = FindLongBinaryOrStringFields(someTableEntity, connectionString);
foreach (var longField in longFields)
{
badFields.Add(longField.Key);
badFieldsReport += longField.Value + "\n";
}
}
else
throw;
}
}
}
The badFieldsReport will have this value:
'SourceData' column cannot take the value of
'Blah-Blah-Blah-Blah-Blah-Blah' because the max length it can take is
16.
It could also be because you're trying to put in a null value back into the database. So one of your transactions could have nulls in them.
Most of the answers here are to do the obvious check, that the length of the column as defined in the database isn't smaller than the data you are trying to pass into it.
Several times I have been bitten by going to SQL Management Studio, doing a quick:
sp_help 'mytable'
and be confused for a few minutes until I realize the column in question is an nvarchar, which means the length reported by sp_help is really double the real length supported because it's a double byte (unicode) datatype.
i.e. if sp_help reports nvarchar Length 40, you can store 20 characters max.
Checkout this gist.
https://gist.github.com/mrameezraja/9f15ad624e2cba8ac24066cdf271453b.
public Dictionary<string, string> GetEvilFields(string tableName, object instance)
{
Dictionary<string, string> result = new Dictionary<string, string>();
var tableType = this.Model.GetEntityTypes().First(c => c.GetTableName().Contains(tableName));
if (tableType != null)
{
int i = 0;
foreach (var property in tableType.GetProperties())
{
var maxlength = property.GetMaxLength();
var prop = instance.GetType().GetProperties().FirstOrDefault(_ => _.Name == property.Name);
if (prop != null)
{
var length = prop.GetValue(instance)?.ToString()?.Length;
if (length > maxlength)
{
result.Add($"{i}.Evil.Property", prop.Name);
result.Add($"{i}.Evil.Value", prop.GetValue(instance)?.ToString());
result.Add($"{i}.Evil.Value.Length", length?.ToString());
result.Add($"{i}.Evil.Db.MaxLength", maxlength?.ToString());
i++;
}
}
}
}
return result;
}
With Linq To SQL I debugged by logging the context, eg. Context.Log = Console.Out
Then scanned the SQL to check for any obvious errors, there were two:
-- #p46: Input Char (Size = -1; Prec = 0; Scale = 0) [some long text value1]
-- #p8: Input Char (Size = -1; Prec = 0; Scale = 0) [some long text value2]
the last one I found by scanning the table schema against the values, the field was nvarchar(20) but the value was 22 chars
-- #p41: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [1234567890123456789012]
In our own case I increase the sql table allowable character or field size which is less than the total characters posted from theĀ front end. Hence that resolve the issue.
Simply Used this:
MessageBox.Show(cmd4.CommandText.ToString());
in c#.net and this will show you main query , Copy it and run in database .