ASP.NET Web API - SQL - Retrieving Information - sql

I am having some issues with retrieving information from sql database using ASP.net Web API.
I have tried to use forms, which worked great (using gridview) but when I try to do it using a separate class dedicated to store my specific table information I get this error:
"Index was out of range. Must be non-negative and less than the size of the collection."
This is the code:
public ActionResult Details()
{
List<Employee> employeeList = new List<Employee>();
string CS = ConfigurationManager.ConnectionStrings["EmployeeContext"].ConnectionString;
using (var myConn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("select * from tblEmployee", myConn);
myConn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
int i = 0;
employeeList[i].PersonID = Convert.ToInt32(rdr["PersonID"]);
employeeList[i].Name = rdr["Name"].ToString();
employeeList[i].Gender = rdr["Gender"].ToString();
employeeList[i].City = rdr["City"].ToString();
employeeList[i].DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
i++;
}
return View(employeeList);
}
}
This is the Employee class:
[Table("tblEmployee")]
public class Employee
{
public int PersonID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public int DepartmentID { get; set; }
}
}
I get this error on any of the retrieving information lines.
The table has 5 columns: PersonID(int PK), Name(nvarchar), Gender(nvarchar), City(nvarchar), DepartmentID(int).
I checked many times the columns names to make sure I didn't got those wrong and I double checked the connection string which is also fine (the same code works with gridview using forms API).
Hope someone can help me with this. I didn't find any specific information on that and I guess it's should be easy and I'm doing something wrong here.

You are trying to populate a List<> object by using an index. To populate a List<> you need to use .Add(). You need to change your code from this:
int i = 0;
employeeList[i].PersonID = Convert.ToInt32(rdr["PersonID"]);
employeeList[i].Name = rdr["Name"].ToString();
employeeList[i].Gender = rdr["Gender"].ToString();
employeeList[i].City = rdr["City"].ToString();
employeeList[i].DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
i++;
To this:
Employee emp = new Employee();
emp.PersonID = Convert.ToInt32(rdr["PersonID"]);
emp.Name = rdr["Name"].ToString();
emp.Gender = rdr["Gender"].ToString();
emp.City = rdr["City"].ToString();
emp.DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
employeeList.Add(emp);

When adding a new item to a list, you should use .Add(). Here's one option:
while (rdr.Read())
{
employeeList.Add(new Employee {
PersonID = Convert.ToInt32(rdr["PersonID"]),
Name = rdr["Name"].ToString(),
Gender = rdr["Gender"].ToString(),
City = rdr["City"].ToString(),
DepartmentID = Convert.ToInt32(rdr["DepartmentID"])
});
}
You could then access individual items in the list with their index or by using foreach.

Related

Custom Model as Generic TypeArgument in XAML

I have made a small class, which inherits from DataGrid and takes in classes that derive from a specific interface:
public class RecordDataGrid<T> : DataGrid where T : IRecord
{
public RecordDataGrid()
{
this.AutoGenerateColumns = false;
this.CanUserAddRows = false;
this.CanUserDeleteRows = false;
this.CanUserResizeRows = false;
this.IsReadOnly = true;
this.SelectionMode = DataGridSelectionMode.Single;
this.Margin = new System.Windows.Thickness(0, 10, 0, 0);
var propertyInfos = typeof(T).GetProperties();
var list = new Dictionary<PropertyInfo, DataGridColumnAttribute>();
foreach (var propertyInfo in propertyInfos)
{
var customAttributes = propertyInfo.GetCustomAttributes(true);
foreach (var customAttr in customAttributes)
{
if (customAttr != null && customAttr is DataGridColumnAttribute)
{
list.Add(propertyInfo, (DataGridColumnAttribute)customAttr);
}
}
}
var ordered = (from entry in list orderby entry.Value.OrderIndex ascending select entry).ToDictionary(e => e.Key, e => e.Value);
foreach (var kvp in ordered)
{
var propertyInfo = kvp.Key;
var dgcAttr = kvp.Value;
var column = new DataGridTextColumn();
column.Header = dgcAttr.DisplayName;
column.Binding = new Binding(propertyInfo.Name);
column.Binding.StringFormat = dgcAttr.StringFormat ?? null;
column.Width = dgcAttr.ColumnWidthType == DataGridColumnAttribute.ColumnWidthTypes.Auto ? new DataGridLength(10, DataGridLengthUnitType.Auto) : new DataGridLength(10, DataGridLengthUnitType.Star);
this.Columns.Add(column);
}
}
}
It is very rough at the moment, just testing a few things out. The goal is to make my life easier by letting the DataGrid fill the Columns by itself, based on a custom Attribute:
public class DataGridColumnAttribute : Attribute
{
public string DisplayName { get; private set; }
public string StringFormat { get; private set; }
public ColumnWidthTypes ColumnWidthType { get; private set; }
public int OrderIndex { get; private set; }
public DataGridColumnAttribute(string displayName, int orderIndex, string stringFormat = null, ColumnWidthTypes columnWidthType = ColumnWidthTypes.Auto)
{
DisplayName = displayName;
StringFormat = stringFormat;
OrderIndex = OrderIndex;
ColumnWidthType = columnWidthType;
}
public enum ColumnWidthTypes
{
Auto,
Fill
}
}
Later on, as far as I am concerned, I should be able to use it in xaml like this:
Namespaces:
xmlns:model="clr-namespace:NickX.KswErp.Model.Classes;assembly=NickX.KswErp.Model"
xmlns:ctrl="clr-namespace:NickX.KswErp.ClientApplication.UI.Controls"
Control:
<ctrl:RecordDataGrid x:Name="_gridTransactions" x:TypeArguments="model:TransactionRecord" />
But I get following compilation error:
Only a master tag can specify the "x: TypeArguments" attribute.
(Roughly translated by google translation)
Maybe my approach is completely wrong tho. Should I do it completle in code behind. Or are there better approaches? Please let me know!
Conveniently I just found a thread in a german forum, which answeres my exact question. So people questioning the same in the future:
It is not possible. Easiest thing to do at this point is making a specific class for each model, which again derives from your generic class.
In my case:
public class TransactionDataGrid : RecordDataGrid<TransactionRecord>
{
}
Doesen't seem like a nice solution to me, and probably isn't the best way to do it. But it works.

Automatically mapping output parameters with Dapper

I've been using Dapper to call stored procedures passing it an object. For example:
If I have an object:
public int ID { get; set; }
public int Year { get; set; }
I can create this object and pass it to my Execute call as the parameters. Dapper automatically maps all of those properties into parameters and executes the stored procedure. Awesome.
What about output parameters? If my object looked like the following how can I get Dapper to populate that property with the output parameter value?
public int ID { get; set; }
public int Year { get; set; }
public int OutputParameter { get; set; }
Do output parameters have to be added as DynamicParameters?
Something like this:
DynamicParameters _params = new DynamicParameters();
_params.Add("#newId", DbType.Int32, direction: ParameterDirection.Output);
var result = connection.Execute("[dbo].YourProc", _params, null, null, CommandType.StoredProcedure);
var retVal = _params.Get<int>("newId");
DynamicParameters _params = new DynamicParameters(new {
ID = 123,
Year = 2020,
OutputParameter = 0
});
_params.Add("OutputParameter", 0, direction: ParameterDirection.Output);
var result = connection.Execute("[dbo].YourProc", _params, commandType: CommandType.StoredProcedure);
var retVal = _params.Get<int>("OutputParameter");
Here's what I've used to create a generic method for calling stored procedures with generic output parameters.
public void CallProcedure<I, O>(
string storedProcedure,
I inputParameters,
O outputParameters,
string connectionId = "Default")
{
using IDbConnection connection =
new SqlConnection(_config.GetConnectionString(connectionId));
var dynamicParameters = new DynamicParameters();
if (inputParameters != null)
dynamicParameters.AddDynamicParams(inputParameters);
if (outputParameters != null)
foreach (PropertyInfo prop in outputParameters.GetType().GetProperties())
dynamicParameters.Add(prop.Name,
prop.GetValue(outputParameters),
GetDbType(prop.PropertyType),
ParameterDirection.Output);
connection.ExecuteAsync(storedProcedure, dynamicParameters,
commandType: CommandType.StoredProcedure);
if (outputParameters != null)
foreach (PropertyInfo prop in outputParameters.GetType().GetProperties())
{
var method = typeof(DynamicParameters)
.GetMethod("Get")
.MakeGenericMethod(new Type[] { prop.PropertyType });
var outputParamValue = method.Invoke(dynamicParameters, new object[] { prop.Name });
prop.SetValue(outputParameters, outputParamValue);
}
}
What you are looking for is the last few lines, below the second if (outputParameters != null)
I do not know how fast it is, as this code is a part of a sketch project.
I also asked this question 6 years later, so you can check if anyone answered it here: Get all stored procedure output parameters using generic type in dapper
All in all this is a good headsup for dapper team to create a simple method we can call to get all output parameters of a stored procedure, instead of us getting into reflection.

not able to create constructor of model class and getting object reference not set to instance of object error

this is my Model:
public class UserDetails
{
public string UserName { get; set; }
public virtual Category Category { get; set; }
}
this is my query to fetch user details along with category:
var data = (from temp in context.UserDetails.Include("Category") select temp).OrderBy(c => c.UserId);
this is how i am accessing on controller:
List<UserDetails> staffDetails = staffBal.fetchStaffDetails();
var categoryModel = new CategoryModel();
Data = staffDetails.Select(x =>
{
var userDetailModel = new UserDetailsModel();
userDetailModel.UserId = x.UserId;
userDetailModel.FName = x.FName;
categoryModel.CategoryName = x.Category.Name;//i am getting error on this line.object reference not set to instance of object
can anybody tell me what is the solution???
You say in your comment: for some records it is coming null for some records it is not null meaning that x.Category is null. Therefore, any attempt to access x.Category.Name will fail. Change the line to this:
categoryModel.CategoryName = x.Category == null ? "" : x.Category.Name;

ServiceStack.ORMLite: Custom query to custom Poco with Sql.In selections?

Background
I'm attempting to use ServiceStack.OrmLite to grab some values (so I can cache them to run some processing against them).
I need to grab a combination of three values, and I have a custom SQL statement that will yield them (does the joins, etc.)
Because this will be a large list of combinations, I'd like to pass in some lists of values and use Sql.In to filter to only the results that have those values.
Specifics
I need to check whether an invoice is unique to a firm and another value (called ClaimLawsuitID here).
so have my poco:
public class FirmIDClaimLawsuitIDInvoiceNumberCombination
{
public string FirmID { get; set; }
public string ClaimLawsuitID { get; set; }
public string InvoiceNumber { get; set; }
}
and I have my SQL statement:
select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)
I would like to run the following:
public List<FirmIDClaimLawsuitIDInvoiceNumberCombination> GetFirmIDClaimLawsuitIDInvoiceNumberCombinationsForExistingItems(IEnumerable<int> firmIds, IEnumerable<long> claimLawsuitIDs, IEnumerable<string> invoiceNumbers)
{
var sql = #"select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)";
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<tblClaimLawsuit>();
var firmFilter = PredicateBuilder.True<tblDefenseInvoice>();
var claimLawsuitFilter = PredicateBuilder.True<tblDefInvClaimantDetail>();
var invoiceNumberFilter = PredicateBuilder.True<tblDefInvClaimantDetail>();
firmFilter = x => Sql.In(x.FirmID, firmIds);
claimLawsuitFilter = x => Sql.In(x.ClaimLawsuitID, claimLawsuitIDs);
invoiceNumberFilter = x => Sql.In(x.InvoiceNumber, invoiceNumbers);
ev.Select(sql);
ev.Where(firmFilter);
ev.Where(claimLawsuitFilter);
ev.Where(invoiceNumberFilter);
return dal.DB.Select<FirmIDClaimLawsuitIDInvoiceNumberCombination>(ev.ToSelectStatement());
}
Question
Is this possible to achieve this way?
Is there some other way of achieving this within ServiceStack's OrmLite that is cleaner and I'm unaware of?
Since I was selecting to a POCO, I simply needed to add the filters based on that POCO.
The following worked just fine:
public List<FirmIDClaimLawsuitIDInvoiceNumberCombination>
GetFirmIDClaimLawsuitIDInvoiceNumberCombinationsForExistingItems(
IEnumerable<long> firmIds,
IEnumerable<long> claimLawsuitIDs)
{
var sql = #"select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)";
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
var firmFilter = PredicateBuilder.True<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
var claimLawsuitFilter = PredicateBuilder.True<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
firmFilter = x => Sql.In(x.FirmID, firmIds);
claimLawsuitFilter = x => Sql.In(x.ClaimLawsuitID, claimLawsuitIDs);
ev.Select(sql);
ev.Where(firmFilter);
ev.Where(claimLawsuitFilter);
return dal.DB.Select<FirmIDClaimLawsuitIDInvoiceNumberCombination>(ev.ToSelectStatement());
}

How to get single row from SQLite database in Windows Store apps?

If I want single primitive value like int, string, float etc I can do like this.
using (var db = new SQLiteConnection(DbPath))
{
double i = db.CreateCommand("select salary from PersonMaster where personId = ?", 9).ExecuteScalar<double>();
}
If I try to return whole object of person master i.e. single row the below code returns null
using (var db = new SQLiteConnection(DbPath))
{
PersonMaster objPersonMaster = db.CreateCommand("select * from PersonMaster where personId = ?", 9).ExecuteScalar<PersonMaster>();
}
I compulsory have to use this
using (var db = new SQLiteConnection(DbPath))
{
List<PersonMaster> lstPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9);
PersonMaster objPersonMaster = lstPersonMaster.First();
}
Is there any way to get single row as object, rather than dealing with List<T>
I am assuming you are using SQLite-Net. If that is the case you can use the Find method. Find gets an object using its primary key.
The personId field needs the PrimaryKey attribute as follows:
public class PersonMaster
{
[PrimaryKey]
public int personId { get; set; }
public string name { get; set; }
public decimal salary { get; set; }
}
Then you can use Find like so:
// get person 9
PersonMaster person9 = db.Find<PersonMaster>(9);
You can either use "TOP(1) yourquery" or "yourquery LIMIT 1"
if you just want to get rid of the list step, you can do it directly:
PersonMaster objPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9).First();
Of course you have to deal with a possible exception in case nothing is returned, but you should do this also with the list approach anyway.