How to correct DoNotExposeGenericLists error C# - c#

I have the following method in DAL which accepts the model OrderList and returns a List<OrderList>
public List<OrderList> GetOrderList(OrderList orderList)
{
...
return new List<OrderList>();
}
When I analyze using FXCop, it's saying DoNotExposeGenericLists Error
FXCop is saying this as resolution
"Change 'List<OrderList>' in 'OrderRelatedDataAccess.GetOrderList(OrderList)' to use
Collection<T>, ReadOnlyCollection<T> or KeyedCollection<K,V>"
How can I correct this?
My OrderList model is shown below
public int serialNumber { get; set; }
public int orderID { get; set; }
public int orderListID { get; set; }
public int productID { get; set; }
public int quantity { get; set; }
public long price { get; set; }
public string productName { get; set; }
Thanks.
Edit:
Code inside the method
List<OrderList> listOfOrderList = new List<OrderList>();
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("sGetOrderListByOrderID", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#orderID", orderList.orderID);
connection.Open();
reader = command.ExecuteReader();
int sno = 0;
while (reader.Read())
{
long price = long.Parse(reader[4].ToString());
listOfOrderList.Add(new OrderList()
{
serialNumber = ++sno,
orderID = (int)reader[0],
productID = (int)reader[2],
quantity = (int)reader[3],
price = price,
productName = reader[5].ToString(),
});
}
connection.Close();
}
return listOfOrderList;

In your case its best to change the method signature to use an IList instead of List
public IList<OrderList> GetOrderList(OrderList orderList)
{
//get your data and build your list here
return new List<OrderList>();
}
See the differences between ICollection and IList in this answer

The answer is right there in the FxCop message. Just change the return type to be ICollection<OrderList>, like so:
public ICollection<OrderList> GetOrderList(OrderList orderList)
{
...
return new List<OrderList>();
}

Related

Dapper - How to create class instance by column value?

How to instantiate class by specific column value with Dapper?
Let's say we have table 'items' with columns: ID, Type, Name...
And, when Type is equal to "Burger", class Burger should be instantiated, when Type is "Sandwich", class Sandwich should be instantiated.
First approach that comes to my mind is to execute query for every type, for example:
var sandwiches = conn.Query<Sandwich>("SELECT * FROM items WHERE Type = 'Sandwich'");
var burgers = conn.Query<Burger>("SELECT * FROM items WHERE Type = 'Burger'");
But this approach is expensive because we will have as many queries as number of item types.
Can we do the same job with single query? (Select all rows and create instances based on column value)
A class could have a generic method that could do what you want:
public class Query
{
public IEnumerable<T> GenericQuery<T>(string query)
{
using (SqlConnection cnn = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;"))
{
cnn.Open();
return cnn.Query<T>(query);
}
}
}
Now you can call it in this way
void Main()
{
var q = new Query();
var sandwiches = q.GenericQuery<Sandwich>("SELECT * FROM items WHERE Type = 'Sandwich'");
var burgers = q.GenericQuery<Burger>("SELECT * FROM items WHERE Type = 'Burger'");
}
use method's generic argument to get type
public class ItemsRepository
{
private const string Query = "SELECT * FROM items WHERE Type = #Type";
public async Task<IEnumerable<T>> GetItemsBasedOnTypeAsync<T>()
{
await using var connection = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;");
await connection.OpenAsync();
var parameters = new { Type = nameof(T) };
return connection.Query<T>(Query, parameters);
}
}
now you can call method for any items type
var itemsRepository = new ItemsRepository();
var sandwiches = await itemsRepository.GetItemsBasedOnTypeAsync<Sandwich>();
var burgers = await itemsRepository.GetItemsBasedOnTypeAsync<Burger>();
V2(select all items):
use can do something like this, or cast to base interface if exists.
public class Item
{
public int Id { get; set; }
public string Type { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class Sandwich
{
public Sandwich(Item item)
{
Id = item.Id;
Property1 = item.Property1;
Property2 = item.Property2;
}
public int Id { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class Burger
{
public Burger(Item item)
{
Id = item.Id;
Property1 = item.Property1;
Property2 = item.Property2;
}
public int Id { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class ItemsRepository
{
private const string Query = "SELECT * FROM items";
public async Task<IEnumerable<object>> GetItemsBasedOnTypeAsync()
{
await using var connection = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;");
await connection.OpenAsync();
var items = connection.Query<Item>(Query);
var objects = items.Select(Create)
.ToList();
return objects;
}
private object? Create(Item item) =>
Assembly
.GetExecutingAssembly()
.CreateInstance(item.Type,true,BindingFlags.Public,null,
new object[]{item},
CultureInfo.DefaultThreadCurrentCulture, null);
}

The number of values in the VALUES clause must match the number of columns specified in the INSERT statement

This is my models class (ObjektiMeQira.cs):
namespace crud2.Models
{
public class ObjektiMeQira
{
public int ObjektiMeQiraId { get; set; }
public string ObjektiMeQiraEmri { get; set; }
public string LlojiObjektit { get; set; }
public string Siperfaqe { get; set; }
public int NumriIDHomave { get; set; }
public string Kati { get; set; }
public int Cmimi { get; set; }
public string Vendndodhja { get; set; }
public string Qyteti { get; set; }
public string Shteti { get; set; }
}
}
And now this is my Controllers class (ObjektiMeQiraController.cs):
Note: I am only getting this error in Post method, otherwise Get method works fine.
[HttpPost]
public JsonResult Post(ObjektiMeQira omq)
{
string query = #"
insert into dbo.ObjektiMeQira(ObjektiMeQiraEmri,LlojiObjektit,Siperfaqe,
NumriIDHomave, Kati, Cmimi, Vendndodhja, Qyteti, Shteti)
values (#ObjektiMeQiraEmri), (#LLojiObjektit), (#Siperfaqe),
(#NumriIDHomave), (#Kati), (#Cmimi), (#Vendndodhja), (#Qyteti), (#Shteti)
";
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString("EmployeeAppCon");
SqlDataReader myReader;
using (SqlConnection myCon = new SqlConnection(sqlDataSource))
{
myCon.Open();
using (SqlCommand myCommand = new SqlCommand(query, myCon))
{
myCommand.Parameters.AddWithValue("#ObjektiMeQiraEmri", omq.ObjektiMeQiraEmri);
myCommand.Parameters.AddWithValue("#LlojiObjektit", omq.LlojiObjektit);
myCommand.Parameters.AddWithValue("#Siperfaqe", omq.Siperfaqe);
myCommand.Parameters.AddWithValue("#NumriIDHomave", omq.NumriIDHomave);
myCommand.Parameters.AddWithValue("#Kati", omq.Kati);
myCommand.Parameters.AddWithValue("#Cmimi", omq.Cmimi);
myCommand.Parameters.AddWithValue("#Vendndodhja", omq.Vendndodhja);
myCommand.Parameters.AddWithValue("#Qyteti", omq.Qyteti);
myCommand.Parameters.AddWithValue("#Shteti", omq.Shteti);
myReader = myCommand.ExecuteReader();
table.Load(myReader);
myReader.Close();
myCon.Close();
}
}
return new JsonResult("Added Successfully");
}
Even though I looked at other posts in stackoverflow I didn't quite find the solution.
Your insert query in C# is just plain wrong - it should be:
string query = #"INSERT INTO dbo.ObjektiMeQira (ObjektiMeQiraEmri, LlojiObjektit, Siperfaqe,
NumriIDHomave, Kati, Cmimi, Vendndodhja, Qyteti, Shteti)
VALUES (#ObjektiMeQiraEmri, #LLojiObjektit, #Siperfaqe,
#NumriIDHomave, #Kati, #Cmimi, #Vendndodhja, #Qyteti, #Shteti);";
You MUST NOT put each parameter into its own round parenthesis!
You need to provide one row of data, with a total of 9 column values - in a single VALUES (.....) statement.

display more than one database query in .net MVC

I am creating my first project using asp.net MVC - I have successfully connected to the database and displayed the information on the index page. My question is how do I get more than one query result on the one index page
for e.g
SELECT student ID,first name,surname FROM STUDENT Notes WHERE student ID = 7
Do I need to create new controllers/models for each query or need to add to the current and if I add to the current how would I do it? Below is the code I currently have in my controller.
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
//int sNumber = 1;
List<CustomerModel> customers = new List<CustomerModel>();
string constr = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
using (MySqlConnection con = new MySqlConnection(constr))
{
string query = "SELECT title, `first name`, surname FROM `STUDENT REGISTER`";
using (MySqlCommand cmd = new MySqlCommand(query))
{
cmd.Connection = con;
con.Open();
using (MySqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
customers.Add(new CustomerModel
{
// CustomerId = Convert.ToInt32(sdr["Student Number"]),
Title = sdr["title"].ToString(),
Name = sdr["first name"].ToString(),
Surname = sdr["surname"].ToString()
});
}
}
con.Close();
}
}
return View(customers);
}
Create a view model with two result set for e.g. Student and Marks
public class Result
{
public Student Student { get; set; }
public Marks Marks { get; set; }
}
Load/Construct this Result view model in controller /service with appropriate data and pass this view model to view.
I hope this helps!
You have to create a new class with all the properties you want to display in your View.
Example:
public class StudentModel {
public int Id { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public strign Surname { get; set; }
}
public class MarkModel {
public int Id { get; set; }
public int StudentId { get; set; }
public int SubjectId { get; set; }
public int Mark { get; set; }
}
public class ResultModel
{
public StudentModel Student { get; set; }
public List<MarkModel> Marks { get; set; }
}
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
//int sNumber = 1;
var model= new ResultModel{
Student = new StudentModel(),
Marks = new List<MarkModel>();
}
string constr = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
using (MySqlConnection con = new MySqlConnection(constr))
{
string queryStudent = "SELECT id, title, `first name`, surname FROM `STUDENT` WHERE Id=1";
using (MySqlCommand cmd = new MySqlCommand(queryStudent))
{
cmd.Connection = con;
using (MySqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
model.student.Id = Convert.ToInt32(sdr["id"]),
model.student.Title = sdr["title"].ToString(),
model.student.Name = sdr["first name"].ToString(),
model.student.Surname = sdr["surname"].ToString()
}
}
}
string queryMarks = "SELECT Id, `StudentId`, StudentId,Mark FROM `MARK` WHERE StudentId=1";
using (MySqlCommand cmd = new MySqlCommand(queryMarks))
{
cmd.Connection = con;
using (MySqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
model.Marks.Add(new MarkModel
{
Id = Convert.ToInt32(sdr["Id"]),
StudentId = Convert.ToInt32(sdr["StudentId"]),
StudentId = Convert.ToInt32(sdr["StudentId"]),
Mark = Convert.ToInt32(sdr["Mark"]),
});
}
}
}
}
return View(model);
}
You should create a new ViewModel class with all the properties you want to display in your View. Then you model your View after it.
From the properties you provided so far, the class should look like this:
public class StudentViewModel {
public int Id { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public strign Surname { get; set; }
}
Then you do the value x property assignment
string query = "SELECT title, `first name`, surname FROM `STUDENT REGISTER`";
List<StudentViewModel> model = new List<StudentViewModel>();
using (MySqlCommand cmd = new MySqlCommand(query)) {
cmd.Connection = con;
con.Open();
using (MySqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
model.Add(new StudentViewModel
{
Id = Convert.ToInt32(sdr["StudentNumber"]),
Title = Convert.ToString(sdr["title"]),
Name = Convert.ToString(sdr["first name"]),
Surname = Convert.ToString(sdr["surname"])
});
}
}
con.Close();
}
return View(model);

Using switch to select enum value

I am new to programming so i don't know what i am doing.
I am pulling enum value from different class and set them as getter and setter.
namespace DataLayer.Entities
{
public enum CourseModeOfDelivery
{
Online, ClassRoom, ELearning,
}
public class Course
{
public int ID { get; set; }
public String CourseName { get; set; }
public String Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public CourseModeOfDelivery CourseMode { get; set; }
}
reading this value in courseRepository
public static Course GetCourse(int id)
{
Course a = new Course();
String GetCommand = "Select CourseName, Description, StartDate, EndDate, CourseMode from Course" + "Where ID = #CourseID";
SqlConnection connection = DBManager.GetSqlConnection();
SqlCommand command = new SqlCommand(GetCommand, connection);
command.Parameters.AddWithValue("#StudentID", id);
try
{
var reader = command.ExecuteReader();
//Read the Command Object and then return details
if (reader.HasRows)
{
while (reader.Read())
{
a.ID = Convert.ToInt32(reader["ID"]);
a.CourseName = reader["CourseName"].ToString();
a.Description = reader["Description"].ToString();
a.StartDate = DateTime.Parse(reader["StartDate"].ToString());
a.EndDate = DateTime.Parse(reader["EndDate"].ToString());
var selection = CourseModeOfDelivery.ClassRoom;
switch (selection)
{
case CourseModeOfDelivery.ClassRoom:
a.CourseMode = CourseModeOfDelivery.ClassRoom;
return a.CourseMode;
case CourseModeOfDelivery.ELearning:
a.CourseMode = CourseModeOfDelivery.ELearning;
return a.CourseMode;
case CourseModeOfDelivery.Online:
a.CourseMode = CourseModeOfDelivery.Online;
return a.CourseMode;
}
a.CourseMode =
}
}
else
{
reader.Close();
}
}
The requirement is to use switch but don't know how to pull data in there.
It depends on the type of database field you use.
If it is int then:
a.CourseMode = (CourseModeOfDelivery) reader["CourseMode"];
If it is String then:
a.CourseMode = (CourseModeOfDelivery) Enum.Parse(typeof(CourseModeOfDelivery), reader["CourseMode"].toString());
The following might also help you:
https://msdn.microsoft.com/en-us/library/essfb559(v=vs.110).aspx
Cast int to enum in C#

How do I extend a model class to another model?

I am trying to extend a class to another class that will collect them as a list.
model:
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public string Guid { get; set; }
public float Rating { get; set; }
public string Industry { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string CountryCode { get; set; }
public virtual Snapshot Snapshot { get; set; }
}
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Email { get; set; }
public DateTime DateTimeSent { get; set; }
public string Subject { get; set; }
public string Html { get; set; }
public string Image { get; set; }
public string Unsubscribe { get; set; }
}
public class BrandSnaphotViewModel
{
public Brand Brand { get; set; }
public List<Snapshot> SnapshotItems { get; set; }
}
controller:
public ActionResult Index(string brandGuid)
{
BrandSnaphotViewModel viewModel = new BrandSnaphotViewModel();
Brand brand = GetBrand(brandGuid);
viewModel.Brand = brand;
List<Snapshot> snapshot = GetBrandSnapshots(brand.BrandId);
viewModel.SnapshotItems = snapshot;
List<BrandSnaphotViewModel> viewModelList = new List<BrandSnaphotViewModel>();
viewModelList.Add(viewModel);
return View(viewModelList.AsEnumerable());
}
private Brand GetBrand(string brandGuid)
{
Brand brand = new Brand();
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT *, industries.name AS industry_name FROM brands LEFT JOIN industries ON brands.industry_id = industries.industry_id WHERE brand_guid = '" + brandGuid.ToString() + "' AND private = 0 LIMIT 1";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
if (dbResult.Read())
{
brand.Guid = dbResult["brand_guid"].ToString();
brand.BrandId = Convert.ToInt32(dbResult["brand_id"]);
brand.Industry = dbResult["industry_name"].ToString();
}
dbResult.Close();
dbConn.Close();
return brand;
}
private List<Snapshot> GetBrandSnapshots(int brandId)
{
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT * FROM snapshots WHERE brand_id = " + brandId + " AND archive = 0 ORDER BY date_sent DESC";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
List<Snapshot> snapshots = new List<Snapshot>();
while (dbResult.Read())
{
snapshots.Add(new Snapshot
{
SnapshotId = Convert.ToInt32(dbResult["snapshot_id"]),
Subject = dbResult["subject"].ToString(),
DateTimeSent = Convert.ToDateTime(dbResult["date_sent"]),
Image = dbResult["image"].ToString(),
Email = dbResult["email"].ToString(),
ContentType = dbResult["content_type"].ToString(),
Type = dbResult["type"].ToString()
});
}
dbResult.Close();
dbConn.Close();
return snapshots;
}
edit
FIXED
The issue was the VIEW was not referencing the ViewModel as an IENumerable<>. FACEPALM.
#model IEnumerable<projectvia.ViewModels.BrandSnaphotViewModel>
#{
ViewBag.Title = "Index";
}
#foreach(var item in Model)
{
#item.Brand.Guid;
for(int i = 0; i< #item.SnapshotItems.Count; i++)
{
#item.SnapshotItems[i].Subject<br/>
}
}
That resolved the issue.
Thank you both experts for the insights... i took both advice and came to this solution.
you are doing wrong, it is a list.
you cannot add element this way. Create object and add that object in list by calling Add()
do like this to add items in it:
List<BrandEmailList> brandSnapshotsList = new List<BrandEmailList>();
while (dbResult.Read())
{
BrandEmailList brandSnapshots = new BrandEmailList (); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
EDIT:
List is a generic thing, you don't need to create a class for it. you can just instantiate a list and add items in it.
why are you doing like that you can do it this way simply:
List<Snapshot> brandSnapshotsList = new List<Snapshot>();
while (dbResult.Read())
{
Snapshot brandSnapshots = new Snapshot(); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
Building on what Ehsan Sajjad did, looking at public IEnumerator<Snapshot> BrandEmails, i believe what you look for looks more like this:
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
// ...
}
public class BrandEmailList : List<Snapshot>
{
}
You need not even create a new type for your brand email list, you can use List<Snapshot> directly.
public ViewResult Whatever() {
var brand = GetBrand(brandName);
var brandSnapshots = GetBrandSnapshots();
return View(brand, brandSnapshots);
}
private Brand GetBrand(string brandName)
{
try
{
var brand = new Brand();
brand.Name = brandName;
// database stuffs ...
return brand;
}
catch (Exception ex)
{
throw ex;
}
}
private List<Snapshot> GetBrandSnapshots()
{
// ...
// DB stuffs -- that *really* should not be in the controller anyways.
// ...
var snapshots = new List<BrandEmailList>();
while (dbResult.Read())
{
// object initializer syntax
snapshots.Add(new Snapshot {
ID = Convert.ToInt32(dbResult["snapshot_id"]),
Guid = dbResult["snapshot_guid"].ToString(),
DateTimeSent = dbResult["date_sent"],
Subject = dbResult["subject"].ToString(),
Image = dbResult["image"],
});
}
return snapshots
}
As a side note, mixing database access into controller methods can be a bad idea. It does not have to be, but it can be. Generally, fetching data from the database happens at a different "level" than serving a MVC result. MVC controller don't have the "purpose" to talk to a database, that work can/should be delegated to a dedicated type. Compare the single responsibility principle part of the SOLID principles.

Categories