I have a class called WebsiteForm which contains a property List<Survey>.
I also have a stored procedure that returns a record set of WebsiteForm data (minus surveys) and a record set of Survey data. These are temporarily stored in lists called formList and surveyList.
I want to be able to put the relevant surveys from surveyList into the survey list in each formList object, if that makes sense. The relevant ones are where the ID property of WebsiteForm matches the LinkID property of Survey.
I imagine this could be done with LINQ but I'm struggling due to the structure of the data.
Thanks.
public class WebsiteForm
{
public int ID { get; set; }
...
public List<Survey> Surveys { get; set; }
}
public class Survey
{
public int LinkID { get; set; }
...
}
public class CRMService
{
...
public List<WebsiteForm> GetData(string storedProcedure)
{
List<WebsiteForm> formList;
List<Survey> surveyList;
using (IDbConnection sqlConnection = new SqlConnection(ConnectionString))
{
sqlConnection.Open();
try
{
using (var data = sqlConnection.QueryMultiple(storedProcedure, commandType: CommandType.StoredProcedure))
{
formList = data.Read<WebsiteForm>().ToList();
surveyList = data.Read<Survey>().ToList();
// Add surveys from surveyList to each formList item where the LinkID of surveyList matches the ID of formList
}
}
finally
{
sqlConnection.Close();
}
}
return formList;
}
}
I'm using Dapper to map the SQL data to the classes btw.
you can try somthing like this
....
formList = data.Read<WebsiteForm>().ToList();
surveyList = data.Read<Survey>().ToList();
formList.ForEach(fl=>fl.Surveys = surveyList.Where(sl=>sl.LinkID == fl.ID).ToList());
....
Related
I am using Entity Framework 5.0 and I created my database from model. The below is the screenshot of the edmx diagram.
I am working towards to a below structure of data:
On given Client ID give me list of Theader which belongs to that ClientID and its TReports so I modeled my models as below:
public class TReportHeaderModel
{
public int ID { get; set; }
public int ClientID { get; set; }
public string THeaderTitle { get; set; }
public int RowNumber { get; set; }
public IList<TReportModel> TReports { get; set; }
}
public class TReportModel
{
public int ID { get; set; }
public string TReportName { get; set; }
public string URL { get; set; }
public int RowNumber { get; set; }
}
So when I query to get Theaders and its each report for given clientID:
I am listing the headers first for given clientID:
public IList<TReportHeaderModel> GetHeadersByClient(int ClientID)
{
using (var connection = new TReportEntitiesConnection())
{
var clientHeaders= (from st in connection.THeaders
where ClientID == st.ClientID
select new TReportHeaderModel
{
ID=st.ID,
THeaderTitle=st.THeaderTitle,
RowNumber=st.RowNumber
}).ToList();
return (clientHeaders);
}
}
And then to get the list of reports for each title and this is where I am stuck--->
public IList<TReportModel> GetChildReportsByHeader(int THeaderID)
{
using (var connection = new TReportEntitiesConnection())
{
// ....
}
}
Instead of separating it by get the headers by client first and then get the report by header id, is it possible to combine it in one method? sorry for the confusing explanation but I am new to LINQ Query so please understand.
The below is the ideal structure for the UI implemetation:
Client ID =2
Header 1
TReportName
URL
Header 2
TReportName
URL
is it possible to combine it in one method?
If I understand you correctly, this is what you're looking for:
using (var connection = new TReportEntitiesConnection())
{
var clientHeaders = (
from st in connection.THeaders
where ClientID == st.ClientID
select new TReportHeaderModel
{
ID=st.ID,
THeaderTitle = st.THeaderTitle,
RowNumber = st.RowNumber,
Reports = from r in st.TReports
select new TReportModel
{
ID = r.ID,
TReportName = r.TReportName,
URL = r.URL,
RowNumber = r.RowNumber,
}
}
).ToList();
}
return clientHeaders;
Note that for this to work, TReportHeaderModel.TReports should be IEnumerable<TReportModel>.
Normally I would suggest you separate the methods for getting your data and transforming your data into DTOs like this (And usually I have the connection defined at the class level, not at the method level because I will reuse the connection many times, and I prefer keeping my data accesses as lazy as possible):
TReportEntitiesConnection conn = new TReportEntitiesConnection();
Then I will create extension methods like so:
public static class MyExtensions
{
public IQueryable<THeader> ByClientId(this IQuerable<THeader> conn, int ClientID)
{
return conn
.Include(h=>h.Reports)
.Where(h=>h.ClientID==ClientID);
}
public TReportHeaderModel ToDto(this THeader t)
{
return new TReportHeaderModel
{
ID=t.ID,
ClientID=t.ClientID,
THeaderTitle=t.THeaderTitle,
RowNumber=t.RowNumber,
Reports=t.Reports.ToDto()
};
}
public TReportModel ToDto(this TReport r)
{
return new TReportModel
{
ID=r.ID,
TReportName=r.TReportName,
URL=r.URL,
RowNumber=r.RowNumber
};
}
public IEnumerable<TReportHeaderModel> ToDto(this IEnumerable<THeader> h)
{
return h.Select(x=>x.ToDto());
}
public IEnumerable<TReportModel> ToDto(this IEnumerable<TReport> r)
{
return r.Select(x=>x.ToDto());
}
}
Then you can use it like so:
var result=conn.THeaders.ByClientId(200).ToDto();
If you prefer not having your connection at the module level, that is easy too:
using(var connection = new TReportEntitiesConnection())
{
var result=connection.THeaders.ByClientId(200).ToDto();
}
(or use AutoMapper and skip all the manual Dto conversions)
This is my first question here and I'm new to WPF/MVVM.
What I'm trying to do is display a multi-column listview that holds the results returned from a stored procedure.
I'm doing my best to implement MVVM and this is where I'm having trouble.
I have a model (SL_ID is the PK and not nullable in the database):
public class mJob_Select_OrderList
{
public int SL_ID { get; set; }
public string E32JobNumber { get; set; }
public string E32_CLIENT { get; set; }
public string SL_DESCRIPTION { get; set; }
public string E32_DESCRIPTION { get; set; }
}
and then I have a view model:
public class vmJob_Select : vmMain
{
#region Members
Models.mJob_Select _mJobSelectSettings;
public SLEVEN_CLASS.dbSLEVENDataContext _dc;
#endregion
#region Constructors
public vmJob_Select()
{
_dc = new SLEVEN_CLASS.dbSLEVENDataContext();
_mJobSelectSettings = new Models.mJob_Select { EnvironmentID = 1 };
//EnvironmentList
var dsEnvironmentList = (from el in _dc.vw_EnvironmentLists orderby el.ENV_ID select new mJob_Select_Environment { ENV_ID = el.ENV_ID, Environment = el.Environment, IMAGE_RESOURCE = el.IMAGE_RESOURCE });
EnvironmentList = new ObservableCollection<mJob_Select_Environment>(dsEnvironmentList);
//Orders List
var dsSLEVENOrders = _dc.get_SLORDER_List(SelectedEnvironmentID).ToList();
SelectOrderList = new List<mJob_Select_OrderList>(dsSLEVENOrders);
}
#endregion
#region Properties
public Models.mJob_Select mJobSelectSettings { get { return _mJobSelectSettings; } set { _mJobSelectSettings = value; } }
public int SelectedEnvironmentID { get { return mJobSelectSettings.EnvironmentID; } set { if (mJobSelectSettings.EnvironmentID != value) { mJobSelectSettings.EnvironmentID = value; RaisePropertyChanged("EnvironmentID"); } } }
public ObservableCollection<mJob_Select_Environment> EnvironmentList { get; set; }
public List<mJob_Select_OrderList> SelectOrderList { get; set; }
}
So basically EnvironmentList is pulled from a view in the database and I can populate an ObservableCollection successfully. The SelectedOrderList is the result of a stored procedure and I'm trying to load this result into a list object of some sort.
The error I'm getting is
Cannot convert from 'System.Collections.Generic.List' to 'int'
I was able to implement this successfully in the code behind on the view but I'm trying to adhere to MVVM and making my ViewModel do the work.
using (SLEVEN_CLASS.dbSLEVENDataContext dbSLEVEN = new SLEVEN_CLASS.dbSLEVENDataContext())
{
var dsSLEVENOrders = dbSLEVEN.get_SLORDER_List(intENVID);
lvSlevenJobs.ItemsSource = dsSLEVENOrders;
lvSlevenJobs.SelectedValuePath = "SL_ID";
}
I've been searching and trying to figure this out for awhile now and I've tried to implement some solutions that I've found here and there to no avail. One involved looping through the IResult and adding each row to the model another suggested building a more complex linq query instead of a stored procedure. None of these options are out of the question. Is there a generally accepted method for performing this task?
Thanks in advance to any answers/suggestions you can provide!
//EDIT//
I believe I've found my solution. I was trying to return my SPROC results to a model that I created but when using LINQ a Model is created automatically called Procedure Name + 'Result'.
I declared my list to utilize the 'Result' model like so:
public List<get_SLORDER_ListResult> SelectOrderList { get; set; }
List<get_SLORDER_ListResult> lstSLEVENOrders = _dc.get_SLORDER_List(SelectedEnvironmentID).ToList<get_SLORDER_ListResult>();
SelectOrderList = new List<get_SLORDER_ListResult>(lstSLEVENOrders);
I then bound my ListView to SelectOrderList.
I want to create a list based off the query that gets passed into my Method. My issue is determining how to add those items to a list that I return as a result list. The following is the code that includes my list and what will hopefully be the way I populate that list...
public void QueryInto<T>(ref List<T> returnType, string queryString, string[] parameters = null)
{
try
{
// Setup the query.
SetupCommand(queryString);
// Setup the parameters.
AddParameters(parameters);
// Execute the reader.
OpenReader();
// Make sure the statement returns rows...
if (reader.HasRows)
{
// For each row, do this...
while (reader.Read())
{
// TODO: use datamapping to map to model and add items to list...
}
}
}
Perhaps there is a better way of doing this, but so far this is the direction Google Has directed me!
you can use Dapper for this.
example useage;
public class Dog
{
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }
}
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });
I try to add view from this controller . I only need this view to show data not for insert or update or delete
public ActionResult Index()
{
var CartObj = ShoppingCart.GetCart(this.HttpContext);
var classshop = new New
{
CartItems = CartObj.GetCartItems(),
CartTotal = CartObj.GetSum()
};
return View(classshop);
}
namespace MusicStore.Models
{
public class ShoppingCart
{
MusicStoreEntities dbo = new MusicStoreEntities();
string ShoppingCartID { get; set; }
public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(HttpContextBase Context)
{
var cart = new ShoppingCart();
cart.ShoppingCartID = cart.GetCardId(Context);
return cart;
}
public static ShoppingCart GetCart(Controller controller)
{
return GetCart(controller.HttpContext);
}
public List<Cart> GetCartItems()
{
return dbo.Carts.Where(a => a.CartId == ShoppingCartID).ToList();
}
public decimal? GetSum()
{
decimal? Sum = (from items in dbo.Carts
where items.CartId == ShoppingCartID
select (int)items.Count * items.album.Price).Sum();
return Sum ?? decimal.Zero;
}
}
}
and then I got this error:
there was an error running the selected code generator:
'unable to retrieve metadata for 'Musicstore.Model.new'
one or more validation error were detected during model generation
musicstore,models.New :entity type'New' has no key defined .
define the key of entityType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MusicStore.Models
{
public class New
{
public List<Cart> CartItems { get; set; }
public decimal? CartTotal { get; set; }
}
}
There are two options here. First, if this class is mapped to a table in your database, every model in entity framework requires a primary key. Add this into your model:
[Key]
public int Id { get; set; }
This creates a new property called Id and the [Key] attribute makes it a primary key. Technically you don't need the attribute as EF will pick up Id property and use it as a key, but I prefer to be explicit.
Alternatively, if you don't want this class to be a table in your database, add the NotMapped attribute to the class like this:
[NotMapped]
public class New
{
public List<Cart> CartItems { get; set; }
public decimal? CartTotal { get; set; }
}
I know this is old, but I just ran across this issue.
What happen is when I created a class, CreateEmployeeViewModel, inside the Models folder Visual Studio "smartly" put a line in my DB Context class
public System.Data.Entity.DbSet<eManager.Web.Models.CreateEmployeeViewModel>
CreateEmployeeViewModels { get; set; }
So a table was created on the next update-migration. Removing this line removed the requirement for a key field.
Note: You may also have to add the line AutomaticMigrationDataLossAllowed = true; to your DBMigrationConfiguration Class if the table was created.
I have a table called Activity (Mobile service), and i add a query in reading:
Azure Script:
function read(query, user, request)
{
var param = request.parameters.UserLocation;
if(param)
{
var sql = "Select TOP 10 [NewsItemUrl], count(1) as CounterNews FROM [MobileServiceExtra].[ACTIVITY] WHERE [UserLocation] = ? GROUP BY [NewsItemUrl] ORDER BY CounterNews Desc";
mssql.query(sql,param, {success: function(results) {request.respond(statusCodes.OK, results);}});
}
//request.execute();
}
Client side:
public class ACTIVITY
{
public int Id { get; set; }
[JsonProperty(PropertyName = "UserLocation")]
public string _UserLocation { get; set; }
[JsonProperty(PropertyName = "NewsItemUrl")]
public string _NewsItemUrl { get; set; }
[JsonProperty(PropertyName = "NewsItemTitle")]
public string _NewsItemTitle { get; set; }
[JsonProperty(PropertyName = "NewsItemPublisher")]
public string _NewsItemPublisher { get; set; }
}
If I do the query in sql, I get 2 columns CounterNews and NewsItemUrl and where the Last is the number of times to repeat the url. However, I dont know how to get the data in column "CounterNews", i mean, when i want to get the query, i get to do with the Activity table (class) and obviously returns me the data correctly, but only NewsItemUrl column and the other fields are empty.
Client side:
private MobileServiceCollection<ACTIVITY, ACTIVITY> TopReadCollectionActivity;
private IMobileServiceTable<ACTIVITY> ACTIVITYTable = App.MobileService.GetTable<ACTIVITY>();
private async void LoadTop10()
{
var dict = new Dictionary<string, string>
{
{ "UserLocation", "United States" },
};
try
{
TopReadCollectionActivity = await ACTIVITYTable.WithParameters(dict).ToCollectionAsync();
}
catch (Exception ex)
{
string err = ex.Message;
}
}
if i create a class (table too)"Top10", azure give a error, because the table doen't exist. and
not want to create a new table.
how to get the query only two fields CounterNews and NewsItemUrl?
Perhaps you should just query the table directly using the OData support. This way your not confined to the structure of your table. Take a look at this for reference.
http://msdn.microsoft.com/en-us/library/windowsazure/jj677199.aspx