I have a model with a nested collection:
public class SomeClass
{
public SomeClass()
{
this.OtherPart = new HashSet<OtherPart>();
}
[Key]
public int SomeClassId { get; set; }
public string SomeData { get; set; }
public string SomeOtherData { get; set; }
public virtual ICollection<OtherPart> OtherParts { get; set; }
public void CreateOthers(int count = 1)
{
for (int i = 0; i < count; i++)
{
OtherParts.Add(new OtherPart());
}
}
}
with this Controller action:
public ActionResult Create()
{
var abc = new SomeClass();
abc.CreateOthers();
return View(abc);
}
and it works perfectly. The problem I now have is that for my use case i need to set a maximum number of items to create ( in this case 5).
I have tried the following modification in the void above, but it is ignored:
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && count < max; i++)
{
OtherParts.Add(new OtherPart());
}
}
Any suggestions on how to effectively limit the max number of items added to the nested collection?
Thanks!
You probably need a custom validator, similar to this:
public class MaxItemsAttribute : ValidationAttribute
{
private readonly int _max;
public MaxItemsAttribute(int max) {
_max = max;
}
public override bool IsValid(object value) {
var list = value as IList;
if (list == null)
return false;
if (list.Count > _max)
return false;
return true;
}
}
In your model code, just do this:
[MaxItems(5)]
public virtual ICollection<OtherPart> OtherParts { get; set; }
Change to i < max
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && i < max; i++)
{
OtherParts.Add(new OtherPart());
}
Related
i'm trying to store objects in array, but i recive error - System.ArrayTypeMismatchException: 'Attempted to access an element as a type incompatible with the array.' I was looking for answer but still can't figure it out. It seemed to me that if i use arrays of object type i can update array with any type of data...
my code:
{//cass.cs
public class Map
{
private int Rows { get; set; }
private int Cols { get; set; }
private string[,] Grid { get; set; }
private Object[,] BoardTiles { get; set; }
public Map(int rows, int cols)
{
this.Rows = rows;
this.Cols = cols;
this.BoardTiles = new string[rows, cols];
}
public void printBoard(int playerPositionRowIndex, int playerPositionColumnIndex)
{
Floor floor = new Floor("floor", 1);
for (int r = 0; r < Rows; r++)
{
for (int c = 0; c < Cols; c++)
{
if (r == playerPositionRowIndex && c == playerPositionColumnIndex)
{
BoardTiles[r, c] = floor; //this place will be changed
Console.Write("#");
}
else
{
BoardTiles[r, c] = floor;
Console.Write("*");
}
}
Console.WriteLine();
}
}
}
{//floor.cs
public class Floor
{
private string Type { get; set; }
private int Num{ get; set; }
public Floor(string type, int num)
{
this.Type = type;
this.Num = num;
}
}
}
Map map = new Map(5, 10);
map.printBoard(4, 3);
I created a trading system with an adaptive moving average on the average true range but the program reports this error to me
the modifier public is not valid for this item
at line 21 of the code
public int avgTrueRange.value1 { get; set; }
I tried to change public but it always reports this error.
this is the code :
public class MediaMobileAdattiva : SignalObject
{
public MediaMobileAdattiva(object _ctx): base(_ctx)
{
Range = 14;
FirstLength = 10;
AvgTrueRange.value1 = 1;
}
private IOrderMarket buy_order;
public int Range { get; set; }
public double FirstLength { get; set; }
public int AvgTrueRange.value1 { get; set; }
private double FirstAverage()
{
if (AverageTrueRange < AvgTrueRange.value1)
return FirstLength;
}
protected override void Create()
{
// create variable objects, function objects, order objects
buy_order = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.Buy));
}
protected override void StartCalc()
{
// assign inputs
}
protected override void CalcBar()
{
// strategy logic
if (Bars.CurrentBar > 1)
{
switch (FirstAverage)
{
case FirstLength:
return 1;
}
}
if (Bars.CurrentBar > 1 && Bars.Close.CrossesOver(FirstAverage, ExecInfo.MaxBarsBack)
{
switch (FirstLength)
{
case 1:
buy_order.Send(Bars.Close[0]);
}
}
}
}
What you need is to make a struct for AvgTrueRange:
public struct Range
{
public int value1 {get; set;}
}
and change:
public int AvgTrueRange.value1 { get; set; }
to
public Range AvgTrueRange { get; set; }
Your code still won't compile btw but I don't really understand what you are trying to do in this line:
if (AverageTrueRange < AvgTrueRange.value1)
Also, change:
switch (FirstAverage)
{
case FirstLength:
return 1;
}
to
var avg = FirstAverage();
int? result = avg switch
{
var avg when avg == FirstLength => 1,
_ => null
};
if (result.HasValue) return result.Value;
as cases can only be constant values.
I have an SQL Query which returns the following table with 3 columns:
I am searching a data structure, in which I can store the table, that delivers me back the phasename when the dot is between.
I.e. 300 returns Project Management, 360 returns Controlling.
"Project Management"=givePhaseNameFor (300);
"Controlling"=givePhaseNameFor (360);
In SQL I would write
WHERE point IS BETWEEN y1 AND y2
public string givePhaseNameFor(int point)
{
return "Project Management
}
Is there a data structure (like a Dictionary) for this?
No there is not, but you could use something like this:
public class RangeList<T>
{
private List<T> list = new List<T>();
public abstract int GetLower(T item);
public abstract int GetUpper(T item);
public T this[int index]
{
get
{
return list.SingleOrDefault(x => index >= GetLower(x) && index <= GetUpper(x));
}
}
public void Add(T item)
{
if (list.Any(x => GetUpper(item) >= GetLower(x) && GetLower(item) <= GetUpper(x)))
throw new Exception("Attempt to add item with overlapping range");
}
}
public class Phase
{
public int y1;
public int y2;
public string phasename;
}
public class PhaseList : RangeList<Phase>
{
public override int GetLower(Phase item)
{
return item.y1;
}
public override int GetUpper(Phase item)
{
return item.y1;
}
}
Usage:
PhaseList phaseList = GetPhaseListFromDB();
return phaseList[300]?.phasename;
EDIT: An alternate to this would be to create an interface that classes useable in a 'RangeList' must implement. This will mean you don't need a separate inherited list class for each type you want to use.
public interface IRangeable
{
int Lower { get; }
int Upper { get; }
}
public class Phase : IRangeable
{
public int y1;
public int y2;
public string phasename;
int IRangeable.Lower => y1;
int IRangeable.Upper => y2;
}
public class RangeList<T> where T : IRangeable
{
private List<T> list = new List<T>();
public T this[int index]
{
get
{
return list.SingleOrDefault(x => index >= ((IRangeable)x).Lower && index <= ((IRangeable)x).Upper);
}
}
public void Add(T item)
{
if (list.Any(x => ((IRangeable)item).Higher >= ((IRangeable)x).Lower && ((IRangeable)item).Lower <= ((IRangeable)x).Upper))
throw new Exception("Attempt to add item with overlapping range");
}
}
Usage:
RangeList<Phase> phaseList = GetPhaseListFromDB();
return phaseList[300]?.phasename;
class Row
{
public Y1 {get;set;}
public Y2 {get;set;}
public Name {get;set;}
}
var list = new List<Row>();
//fill list
var result = list.Where(o => o.Y1 <= x && x < o.Y2).First();
if you want speed, I would make two arrays:
One containing the start ranges
Another containing the names
Then you would first populate the arrays:
int nbRanges = //Get this info from the number of rows in you table
int[] range = new int[nbRanges];
string[] rangeNames = new string[nbRanges];
for (int i = 0; i < nbRanges; i++)
{
range[i] = //Table.y1;
rangeNames[i] = //Table.phasename;
}
After that, to look for the name is straightforward :
public string givePhaseNameFor(int point)
{
int index = 0;
while (index + 1 < nbRanges)
{
if (point <= range[index + 1])
{
//This means that your point is in the current range
break;
}
else
{
index++; //The point is not in this range
}
}
//If we exit without having it found, index == nbRanges and we return the last value
return rangeNames[index];
}
I implement in my WCF Services tha pagination throught Data Service but not work, the code from the activation is:
public class Profit : DataService<ProfitEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// Set page size defaults for the data service.
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.SetEntitySetPageSize("artEntities", 1);
}
}
I use EF 6 + Linq
I retrieve all my Product indeed without a problem but I need the pagination beacuse is a large data.
Thanks you
Code of my Query:
public List<Product> GetAllProduct()
{
ProfitEntities context = new ProfitEntities();
List<Product> product = new List<Product>();
foreach (artEntities art in context.art)
{
product.Add(new Product
{
coArt = art.co_art.Trim(),
desArt = art.art_des.Trim(),
stockAct = Convert.ToDecimal(art.stock_act),
precVta1 = Convert.ToDecimal(art.prec_vta1),
anulado = art.anulado
});
}
if (product.Count > 0)
{
return product;
}
else
throw new Exception("Imposible conseguir lista de Articulos");
}
Thanks you for your help.
I found other way to make the pagination to WCF Services...
I used a two class found in other proyect from MVC and change to my purpose...
Interface IPagedList
public interface IPagedList<T> : IList<T>
{
int PageCount { get; }
int TotalItemCount { get; }
int PageIndex { get; }
int PageNumber { get; }
int PageSize { get; }
bool HasPreviousPage { get; }
bool HasNextPage { get; }
bool IsFirstPage { get; }
bool IsLastPage { get; }
}
Paged Class
public class PagedList<T> : List<T>, IPagedList<T>
{
public PagedList(IEnumerable<T> source, int index, int pageSize, int? totalCount = null)
: this(source.AsQueryable(), index, pageSize, totalCount)
{
}
public PagedList(IQueryable<T> source, int index, int pageSize, int? totalCount = null)
{
if (index < 0)
throw new ArgumentOutOfRangeException("index", "Value can not be below 0.");
if (pageSize < 1)
throw new ArgumentOutOfRangeException("pageSize", "Value can not be less than 1.");
if (source == null)
source = new List<T>().AsQueryable();
var realTotalCount = source.Count();
PageSize = pageSize;
PageIndex = index;
TotalItemCount = totalCount.HasValue ? totalCount.Value : realTotalCount;
PageCount = TotalItemCount > 0 ? (int)Math.Ceiling(TotalItemCount / (double)PageSize) : 0;
HasPreviousPage = (PageIndex > 0);
HasNextPage = (PageIndex < (PageCount - 1));
IsFirstPage = (PageIndex <= 0);
IsLastPage = (PageIndex >= (PageCount - 1));
if (TotalItemCount <= 0)
return;
var realTotalPages = (int)Math.Ceiling(realTotalCount / (double)PageSize);
if (realTotalCount < TotalItemCount && realTotalPages <= PageIndex)
AddRange(source.Skip((realTotalPages - 1) * PageSize).Take(PageSize));
else
AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
#region IPagedList Members
public int PageCount { get; private set; }
public int TotalItemCount { get; private set; }
public int PageIndex { get; private set; }
public int PageNumber { get { return PageIndex + 1; } }
public int PageSize { get; private set; }
public bool HasPreviousPage { get; private set; }
public bool HasNextPage { get; private set; }
public bool IsFirstPage { get; private set; }
public bool IsLastPage { get; private set; }
#endregion
}
My Operation Contract (Class)
private int defaultPageSize = 10;
ProfitEntities context = new ProfitEntities();
public List<Product> GetAllProduct(string value)
{
var artprofit = context.art.Include("colores").Include("lin_art").Include("sub_lin").Include("cat_art").ToList();
int? page = Convert.ToInt32(value);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
var productListPaged = artprofit.ToPagedList(currentPageIndex, defaultPageSize);
}
I'm, trying to add a method Takings which calculates and returns the total value of all the bookings for this show. If anyone could lead me in the right direction that would be great :)
namespace GCUShows
{
public class Show
{
private string title;
private Dictionary<int, Booking> bookings;
public string Title
{
get { return title; }
set { title = value; }
}
public Show(string title)
{
this.title = title;
this.bookings = new Dictionary<int, Booking>();
}
public void AddBooking(int bookingID, Booking booking)
{
this.bookings.Add(bookingID, booking);
}
public void RemoveBooking(int bookingID, Booking booking)
{
this.bookings.Remove(bookingID);
}
public Takings
{
}
}
namespace GCUShows
{
public enum TicketType
{
Adult,
Child,
Family
}
public class Booking : ITicket
{
private const int LIMIT = 6;
public Show show;
private int bookingID;
public List<ITicket> tickets;
public int BookingID
{
get { return bookingID; }
set { bookingID = value; }
}
public Booking(Show show)
{
this.BookingID = BookingIDSequence.Instance.NextID;
this.show = show;
show.AddBooking(this);
this.tickets = new List<ITicket>();
}
public void AddTickets(int number, TicketType type, decimal fee)
{
if (type == TicketType.Adult)
{
for(int i =0; i < number; i++)
{
tickets.Add(new AdultTicket(show.Title, fee));
}
}
else if (type == TicketType.Child)
{
for(int i=0; i< number; i++)
{
tickets.Add(new ChildTicket(show.Title));
}
}
else if (type == TicketType.Family)
{
for (int i = 0; i < number; i++)
{
tickets.Add(new FamilyTicket(show.Title, fee));
}
}
}
public string PrintTickets()
{
string ticketInfo = "Booking " + bookingID.ToString() + "\n";
foreach (ITicket ticket in tickets)
{
ticketInfo += ticket.Print();
}
return ticketInfo;
}
public decimal TotalCost()
{
decimal totalCost;
foreach (ITicket ticket in tickets)
{
totalCost += ticket.Fee;
}
return totalCost;
}
public override string ToString()
{
return string.Format("{0}: Total Cost={1:c}", bookingID, TotalCost());
}
}
}
Assuming Bookings contains a property int Val, it could look like:
public int Takes()
{
return bookings.Values.Sum(b => b.Val);
}
If Booking has a Cost property, you can do this:
var total = bookings.Sum(x => x.Value.Cost);
Alternatively to other Linq answer you can do the same thing with a foreach
public decimal Takings()
{
decimal runningTotal = 0;
foreach (KeyValuePair<int, Booking> kvp in bookings) {
runningTotal += kvp.Value.TotalCost();
}
return runningTotal;
}
which might look a little less "magic" if you are new to programming.
this is my bookings class
namespace GCUShows
{
public enum TicketType
{
Adult,
Child,
Family
}
public class Booking : ITicket
{
private const int LIMIT = 6;
public Show show;
private int bookingID;
public List<ITicket> tickets;
public int BookingID
{
get { return bookingID; }
set { bookingID = value; }
}
public Booking(Show show)
{
this.BookingID = BookingIDSequence.Instance.NextID;
this.show = show;
show.AddBooking(this);
this.tickets = new List<ITicket>();
}
public void AddTickets(int number, TicketType type, decimal fee)
{
if (type == TicketType.Adult)
{
for(int i =0; i < number; i++)
{
tickets.Add(new AdultTicket(show.Title, fee));
}
}
else if (type == TicketType.Child)
{
for(int i=0; i< number; i++)
{
tickets.Add(new ChildTicket(show.Title));
}
}
else if (type == TicketType.Family)
{
for (int i = 0; i < number; i++)
{
tickets.Add(new FamilyTicket(show.Title, fee));
}
}
}
public string PrintTickets()
{
string ticketInfo = "Booking " + bookingID.ToString() + "\n";
foreach (ITicket ticket in tickets)
{
ticketInfo += ticket.Print();
}
return ticketInfo;
}
public decimal TotalCost()
{
decimal totalCost;
foreach (ITicket ticket in tickets)
{
totalCost += ticket.Fee;
}
return totalCost;
}
public override string ToString()
{
return string.Format("{0}: Total Cost={1:c}", bookingID, TotalCost());
}
}
}