I'm running into an issue executing my connecting and inserting values into SQL Server where it's returning two different errors when using two separate models that have object references from separate classes.
The first stored procedure inserts into two separate tables. The main one has a foreign key, and the second table also has a foreign key, which has a relationship to the table coming from the second stored procedures primary key. Ultimately I am trying to find a way to execute the SQL script to pass in the values at the same time into both of these separate models.
I'm aware that I must insert first into the dbo.spUpload_Insert and then into dbo.spUploadVideo so the 'id' exists before hand. I also have verified if NULL is unchecked in my database it will insert into the appropriate tables without issue.
The first error:
Cannot insert the value NULL into column 'Video ID', table 'userMediaMetaData.dbo.Video Info Data'; column does not allow nulls. INSERT fails
The second error:
Cannot insert the value NULL into column 'ID', table 'userMediaMetaData.dbo.Basic Video Meta'; column does not allow nulls. INSERT fails
Here's the code causing the error in C# using Dapper for connecting to my database.
I'm using two different models:
public UploadInfo Upload(UploadInfo model)
{
List<String> Title = model.TitleOfVideo;
List <String> Description = model.DescriptionOfVideo;
List <String> Tags = model.Tags;
List <String> ContentId = model.Category;
int count = ContentId.Count;
string title = "";
string description = "";
string tags = "";
string contentID = "";
for (var i = 0; i < count; i++)
{
title = model.TitleOfVideo[i];
description = model.DescriptionOfVideo[i];
tags = model.Tags[i];
contentID = model.Category[i];
}
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("userMediaMetaData")))
{
var parameters = new List<DynamicParameters>();
var p = new DynamicParameters();
p.Add("#Title", title, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#description", description, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#tags", tags, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#ContentID", contentID, dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#id", 0, dbType: DbType.Int32, direction: ParameterDirection.Output);
parameters.Add(p);
connection.Execute("spUploadVideo_Insert", parameters, commandType: CommandType.StoredProcedure);
model.Id = p.Get<int>("#id");
}
return model;
throw new NotImplementedException();
}
Second model:
public ExtractionFullModel Extraction(ExtractionFullModel model)
{
string group = model.Group;
string name = model.Name;
string value = model.Value;
if (count < tot_count)
{
if (name.Contains("Directory"))
{
_directory = name;
_directory_value = value;
}
if (name.Contains("Compatible Brands"))
{
_compatbrand = name;
_compatvalue = value;
}
if (name.Contains("Time Scale"))
{
_timescale = name;
_timescale_value = value;
}
if (name.Contains("Track Duration"))
{
_duration = name;
_duration_value = value;
}
if (name.Contains("Preferred Volume"))
{
_trackvolume = name;
_trackvolume_value = value;
}
if (name.Contains("Track ID"))
{
_trackid = name;
_trackid_value = value;
}
if (name.Contains("Image Width"))
{
_imgwidth = name;
_imgwidth_value = value;
}
if (name.Contains("Image Height"))
{
_imgheight = name;
_imgheight_value = value;
}
if (name.Contains("X Resolution"))
{
_xresolution = name;
_xresolution_value = value;
}
if (name.Contains("Y Resolution"))
{
_yresolution = name;
_yresolution_value = value;
}
if (name.Contains("Video Frame Rate"))
{
_video_frame_rate = name;
_video_frame_rate_value = value;
}
if (name.Contains("Media Create Date"))
{
media_create_date = name;
media_create_date_value = value;
}
if (name.Contains("Modify Date"))
{
_modify_date = name;
_modify_date_value = value;
//modifyDate_value = DateTime.Parse(_modify_date_value);
}
if (name.Contains("Audio Format"))
{
_audioformat = name;
_audioformat_value = value;
}
if (name.Contains("Audio Channels"))
{
_audiochannels = name;
_audiochannels_value = value;
}
if (name.Contains("Audio Bits Per Sample"))
{
_audiobits = name;
_audiobits_value = value;
}
if (name.Contains("Audio Sample Rate"))
{
_audio_sample_rate = name;
_audio_sample_rate_value = value;
}
if (name.Contains("Media Data Size"))
{
_media_data_size = name;
_media_data_size_value = value;
}
if (name.Contains("Image Size"))
{
_image_size = name;
_image_size_value = value;
}
if (name.Contains("Avg Bitrate"))
{
_avg_bitrate = name;
_avg_bitrate_value = value;
}
if (name.Contains("File Size"))
{
_file_size = name;
_file_size_value = value;
}
if (name.Contains("File Modification Date/Time"))
{
_file_mod_date = name;
_file_mod_date_value = value;
//FileModifyDate_value = DateTime.Parse(_file_mod_date_value);
}
if (name.Contains("File Access Date/Time"))
{
_file_access_date = name;
_file_access_date_value = value;
//FileAccessDate_value = DateTime.Parse(_file_access_date_value);
}
if (name.Contains("File Creation Date/Time"))
{
_file_create_date = name;
_file_create_date_value = value;
//FileCreateDate_value = DateTime.Parse(_file_create_date_value);
}
if (name.Contains("File Permissions"))
{
_filepermission = name;
_filepermission_value = value;
}
if (name.Contains("File Type"))
{
_filetype = name;
_filetype_value = value;
}
if (name.Contains("MIME Type"))
{
_MIMEtype = name;
_MIMEtype_value = value;
}
if (name.Contains("Compressor ID"))
{
_compressor = name;
_compressor_value = value;
}
++count;
}
if (count >= tot_count)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("userMediaMetaData")))
{
var p = new DynamicParameters();
p.Add("#id", 0, dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("#FileDirectory", _directory_value);
p.Add("#CompatBrand", _compatvalue);
p.Add("#TimeScale", _timescale_value);
p.Add("#Duration", _duration_value);
p.Add("#TrackVolume", _trackvolume_value);
p.Add("#TrackID", _trackid_value);
p.Add("#ImgWidth", _imgwidth_value);
p.Add("#imgHeight", _imgheight_value);
p.Add("#XResolution", _xresolution_value);
p.Add("#YResolution", _yresolution_value);
p.Add("#VideoFrameRate", _video_frame_rate_value);
p.Add("#MediaCreateDate",media_create_date_value);
p.Add("#ModifyDate", _modify_date_value);
p.Add("#AudioFormat", _audioformat_value);
p.Add("#AudioChannels", _audiochannels_value);
p.Add("#AudioBits", _audiobits_value);
p.Add("#AudioSampleRate",_audio_sample_rate_value);
p.Add("#MediaDataSize",_media_data_size_value);
p.Add("#ImageSize",_image_size_value);
p.Add("#AvgBitRate",_avg_bitrate_value);
p.Add("#FileSize",file_to_int);
p.Add("#FileModDate", _file_mod_date_value);
p.Add("#FileAccessDate", _file_access_date_value);
p.Add("#FileCreateDate", _file_create_date_value);
p.Add("#FilePermission",_filepermission_value);
p.Add("#FileType",_filetype_value);
p.Add("#MIMETYPE",_MIMEtype_value);
p.Add("#CompressorID",_compressor_value);
connection.Execute("dbo.spUpload_Insert", p, commandType: CommandType.StoredProcedure);
model.Id = p.Get<int>("#id");
}
}
return model;
}
Here's the two separate stored procedures in SQL Server.
The first stored procedure with primary key id:
ALTER PROCEDURE [dbo].[spUploadVideo_Insert]
#Title nvarchar(50),
#Description nvarchar(MAX),
#Tags nvarchar(MAX),
#ContentID int,
#id int = 0 output
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.Upload (Title, Description, Tags, [Content ID])
VALUES (#Title, #Description, #Tags, #ContentID);
SELECT #id = SCOPE_IDENTITY();
END
This is the second stored procedure inserting into two tables with the foreign keys:
ALTER PROCEDURE [dbo].[spUpload_Insert]
#FileDirectory nvarchar(50),
#CompatBrand nchar(30),
#TimeScale text,
#Duration nvarchar(15),
#TrackVolume nvarchar(15),
#TrackID nvarchar(50),
#ImgWidth text,
#imgHeight text,
#XResolution nvarchar(50),
#YResolution nvarchar(50),
#VideoFrameRate nvarchar(15),
#MediaCreateDate nvarchar(25),
#ModifyDate nvarchar(25),
#AudioFormat text,
#AudioChannels text,
#AudioBits nchar(10),
#AudioSampleRate nchar(10),
#ImageSize nchar(10),
#MediaDataSize nvarchar(10),
#AvgBitRate nvarchar(50),
#FileSize nvarchar(10),
#FileModDate nvarchar(25),
#FileAccessDate nvarchar(25),
#FileCreateDate nvarchar(25),
#FilePermission nvarchar(50),
#FileType nvarchar(15),
#MIMEType nvarchar(20),
#CompressorID nvarchar(20),
#id int = 0 output
AS
BEGIN
SET NOCOUNT ON;
-- Adding video extraction information
INSERT INTO dbo.[Video Info Data]([File Directory], [Compatible Brands], [Time Scale], [Duration], [Track Volume], [Track ID], [Img Width], [Img Height],
[X Resolution], [Y Resolution], [Video Frame Rate], [Media Create Date], [Modify Date], [Audio Format], [Audio Channels],
[Audio Bits], [Audio Sample Rate], [Media Data Size], [Image Size], [Average Bit Rate], [MIME Type], [Compressor ID])
VALUES (#FileDirectory, #CompatBrand, #TimeScale, #Duration, #TrackVolume, #TrackID, #ImgWidth, #imgHeight, #XResolution, #YResolution, #VideoFrameRate, #MediaCreateDate, #ModifyDate,
#AudioFormat, #AudioChannels, #AudioBits, #AudioSampleRate, #MediaDataSize, #ImageSize, #AvgBitRate, #MIMEType, #CompressorID);
--Adding video extract DATE information
insert into dbo.[Basic Video Meta]([File Directory],[File Size],[File Type],
[File Mod Date],[File Access Date],[File Create Date],[File Permission])
values(#FileDirectory,#FileSize,#FileType,#FileModDate,#FileAccessDate,#FileCreateDate,#FilePermission);
select #id = SCOPE_IDENTITY();
END
So far I have tried moving the method for 'Upload' before the 'Extraction" method thinking that maybe if I insert into the Extraction method first the 'id' would be set and then I wouldn't run into issues once I tried to insert into the database. This just gave me the same "column does not allow nulls" error. I also tried changing how my variables are passed into the methods by changing at what point the 'id' parameter was inserted into the database, this still presented the same result.
Do I need to use some sort of casting, or transaction? and if so do I use this within Dapper and my C# class, or do I need to do this within the stored procedure of my database?
I am creating a website where users can filter the data by brand, storage, price, etc. I want to use a stored procedure to get the data. The problem is that I don't know how to make a stored procedure that accepts a list of strings as parameters.
For example, this is my ASP.NET Core controller:
private readonly contextItem _context;
public ItemsController(contextItem context)
{
_context = context;
}
// GET: api/Items
[HttpGet]
public async Task<ActionResult<IEnumerable<Item>>> GetItem(
string samsung, string iphone, string lg, string _32gb, string _64gb,string _128gb,
string max, string min)
{
List<string> brands = new List<string>(), storage = new List<string>();
string price_min = null, price_max = null;
// brands
if (samsung != null) { brands.Add("samsung"); }
if (iphone != null) { brands.Add("iphone"); }
if (lg != null) { brands.Add("lg"); }
// storage
if (_32gb != null) { storage.Add("32gb"); }
if (_64gb != null) { storage.Add("64gb"); }
if (_128gb != null) { storage.Add("128gb"); }
// price
price_max = max != null ? max : "";
price_min = min != null ? min : "";
string query = $"EXEC SP_Filter #brand ='{string.Join(",", brands)}',#storage='{string.Join(",", storage)}'," +
$"#min='{price_min}',#max='{price_max}'";
return await _context.Item.FromSqlRaw(query).ToListAsync();
}
So the parameters can be more than one, but if they weren't, it would be easy to make a stored procedure like this
create procedure SP_Filter
#brands varchar(250),
#storage varchar(250),
#min decimal,
#max decimal
as
Select *
From Item
Where NAME like '%'+#brands+'%'
and NAME like '%'+#storage+'%'
and PRICE between #min and #max
You can use json or xml. Try this
/* test
DECLARE #Brands nvarchar(4000) SET #Brands = '{"Brands": [{"Brand": "Samsung"}, {"Brand": "iPhone"}, {"Brand": "LG"}, {"Brand": "Xiaomi"}]}';;
DECLARE #Storages nvarchar(4000) SET #Storages = '{"Storages": [{"Storage": "16"}, {"Storage": "32"}, {"Storage": "64"}, {"Storage": "128"}]}';;
SELECT * FROM OPENJSON(#Brands, '$.Brands') WITH ( Brand varchar(20) '$.Brand' );
SELECT * FROM OPENJSON(#Storages, '$.Storages') WITH ( Storage varchar(20) '$.Storage' );
*/
create procedure FilterByBrandStoragePrice
#Brands nvarchar(4000),
#Storages nvarchar(4000),
#min decimal,
#max decimal
as
SELECT *
FROM Item i
WHERE i.Brand in (SELECT * FROM OPENJSON(#Brands, '$.Brands') WITH ( Brand varchar(20) '$.Brand' ))
AND i.Storage in (SELECT * FROM OPENJSON(#Storages, '$.Storages') WITH ( Storage varchar(20) '$.Storage' ))
AND i.PRICE between #min and #max
Here's an example using table value parameters;
CREATE TYPE [TableString] AS TABLE (
Id nvarchar(4000) NULL
)
go
create procedure [name]
#brands [TableString],
...
as
...
public SqlParameter ToSqlParameter(IEnumerable<string> values)
{
var meta = new SqlMetaData("Id", SqlDbType.NVarChar, 4000);
var records = values.Select(v => {
var record = new SqlDataRecord(
meta
);
if (v == null)
record.SetDBNull(0);
else
record.SetString(0, v);
return record;
});
return new SqlParameter()
{
TypeName = "TableString",
SqlDbType = SqlDbType.Structured,
Value = records
};
}
Now you can define that your procedure takes a TableString argument.
You can extend this example slightly, so that you can pass in a TableString into a query;
public class TableValue<T>
{
public T Id { get; set; }
}
public class MyContext : DbContext {
protected override void OnModelCreating(ModelBuilder modelBuilder) {
...
modelBuilder.Entity<TableValue<string>>(e =>
{
e.HasNoKey();
e.ToView("TableString");
e.Property(p => p.Id).HasMaxLength(4000);
});
}
}
var queryable = context.Set<TableValue<string>>()
.FromSqlInterpolated($"select * from {ToSqlParameter( ... )}");
I want to check passport number exist or not ,
before I used this code to check if integer number exist or not ,
but passport number column in MSSQL type varchar(50).
what I tried
1- created stored procedure to read ID No :
create proc [dbo].[VALIDATE_PATIENT_IDNO]
#patient_id varchar(50)
as
select Patient_id from Patients
where Patient_id = #patient_id
2- I created this code in C# to validate id no exist or not :
public int? VALIDATE_PATIENT_IDNO(string patient_id)
{
DAL.DataAccessLayer DAL = new DAL.DataAccessLayer();
DataTable dt = new DataTable();
SqlParameter[] Param = new SqlParameter[1];
Param[0] = new SqlParameter("#patient_id", SqlDbType.VarChar,50);
Param[0].Value = patient_id;
dt = DAL.SelectData("VALIDATE_PATIENT_IDNO", Param);
DAL.close();
if (dt.Rows.Count > 0)
{
DataRow row = dt.Rows[0];
int? patientNumber = row.Field<int>("patient_id");
return patientNumber;
}
// return null otherwise
return null;
}
3- when type the id no or passport no when key down code :
private void textIDNO_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
if (string.IsNullOrEmpty(textIDNO.Text))
{
txtpcfileno.Focus();
}
else
{
var patientNumber = patient.VALIDATE_PATIENT_IDNO(textIDNO.Text); // int?
bool patientExists = patientNumber.HasValue;
if (patientExists == true)
{
MessageBox.Show("Id or Passport No Exist ", "ID EXIST", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return;
}
else
{
txtpcfileno.Focus();
}
}
}
}
4- I have error appeared in the code in step 2 :
Additional information: Specified cast is not valid.
int? patientNumber = row.Field<int>("patient_id");
How to change the code in step 2 and solve this error and check string value not int? ?
Letting the naming confusions (passportnumber vs patientid) aside, you probably don't want to return the found patientids (because you already know them, as they are part of your selection condition) but the count.
Furthermore, your patientid seems to be a string, yet in your result you try to cast this to an integer. That is not possible, thus the error.
You can try as follows:
create proc [dbo].[VALIDATE_PATIENT_IDNO]
#patient_id varchar(50)
as
select count(Patient_id) as patientcount from Patients
where Patient_id = #patient_id
Assuming that patient_id is the primary key of your table, this will either return 1 if a row with the given id exists or 0 if not.
Then you can do
int? patientNumber = row.Field<int>("patientcount");
and then
bool patientExists = patientNumber > 0;
I have an ActionResult to get Parts that relate to the Vendor Selected. When there is a large amount of parts to get it takes a long time to load. In testing the SQL side it has items that probably do not need to be there. Once removed from the query it is fine and retrieves at a good speed. My question is what in the Controller Code is adding this to the query and slowing it down.
Here is my controller code:
[HttpGet]
public ActionResult Add (Guid id)
{
try
{
var userId = User.Identity.GetUserId();
RFQViewModel r = new RFQViewModel();
GeneralEntities cn = new GeneralEntities();
List<PartsViewModel> Apart = new List<PartsViewModel>();
r.selectedParts = db.VendorsMaterialMap.Where(a => a.VendorId == id).Select(a => a.Material.ToString()).ToArray();
Apart = db.Parts.Where(k => r.selectedParts.Contains(k.Material.ToString())).Select(v => new PartsViewModel
{
Material = v.Material,
PartNumber = v.PartNumber,
VendorReference = v.VendorReference,
PartImage = v.PartImage,
UnitOfMeasure = v.UnitOfMeasure
}).ToList();
r.partitem = Apart;
r.RFQId = Guid.NewGuid();
r.vendor = db.Vendors.Where(d => d.VendorId == id).FirstOrDefault();
var Check = db.RFQs.Where(k => k.VendorId == id).OrderByDescending(K => K.CreatedDate).FirstOrDefault();
if (Check != null)
{
var diff = (System.DateTime.Now - Check.RequestDate).Value;
var days = diff.Days;
if (days < 7)
{
ViewBag.msg = "You already created order for This vendor before... <a href='/RFQ/Details/ " + Check.RFQId + "'>Click here</a>";
}
}
return View(r);
}
catch (Exception ex)
{
throw ex;
}
}
On the SQL side this is the query that is running (I have taken the data out but 1):
SELECT
1 AS [C1],
[Extent1].[Material] AS [Material],
[Extent1].[PartNumber] AS [PartNumber],
[Extent1].[VendorReference] AS [VendorReference],
[Extent1].[PartImage] AS [PartImage],
[Extent1].[UnitOfMeasure] AS [UnitOfMeasure]
FROM [dbo].[Parts] AS [Extent1]
WHERE (LOWER( CAST( [Extent1].[Material] AS nvarchar(max))) IN (N'95647db7-00c4-e911-bb01-001c4208b889'
<---- Other Retrieved Data ------>
)) AND (LOWER( CAST( [Extent1].[Material] AS nvarchar(max))) IS NOT NULL)
If I Remove the LOWER and Change the nvarchar(max) to nvarchar(50). The query comes back fast no matter how many record i pull. So What in the above Controller Code is making a GUID nvarchar(max) and taking it to Lower?
Thanks for your help!
So, I'm trying to update rows where LOGIN IS NULL and ID = 1. If there are no rows with these parameters then add new row. I use attach to make that in 1-2 queries so I'm trying to avoid SELECT first and then update.
Problem in NULL value. EF simply ignores LOGIN since it has null value, however I need to find only rows where LOGIN IS NULL. Can I solve that problem without additional SELECT query?
My code:
using (var db = new EntityContext())
{
var ent = new Entity { ID = 1, LOGIN = null };
db.Entities.Attach(ent);
ent.LOGIN = "Whatever";
ent.EMAIL = "Whatever";
int count = db.SaveChanges();
if (count == 0)
{
var clone_ent = new Entity { LOGIN = "Whatever", PASS = "Whatever" };
db.Entities.Add(clone_ent);
db.SaveChanges();
}
}
SQL analog:
UPDATE Entities SET LOGIN = #LOGIN, EMAIL = #EMAIL
WHERE ID = 1 AND LOGIN IS NULL
IF ##ROWCOUNT = 0
INSERT INTO Entities (LOGIN, EMAIL)
VALUES #LOGIN, #EMAIL
Unfortunately, it is not possible to include a WHERE condition into UPDATE statements in entity framework so you will have to select, then update or insert, e.g.:
using (var db = new EntityContext())
{
var ent = db.Entities.Where(x => x.ID == 1 && x.LOGIN == null).FirstOrDefault();
if (ent != null)
{
ent.LOGIN = "Whatever";
ent.EMAIL = "Whatever";
}
else
{
db.Entities.Add(ent);
}
db.SaveChanges();
}