0

I am working with two different databases. I am passing the Model collection (SQL Server) to a ViewModel collection. The ViewModel has extra properties which I access out of a Visual Fox Pro database. I am able to map the existing properties, but the ViewModel does not save the data after passing the values to it.

The WoCust and the Lname fields return null, but the rest of the properties which come from the original Model pass to the properties in the ViewModel fine.

When I debug at the rdr for the OleDbCommand, it shows that the ViewModel is receiving a value for both rdr[WoCust] and rdr[Lname].

How do I make it so the ViewModel saves the new values?

WOSchedule.cs...

public partial class WOSchedule
{
    public long Id { get; set; }
    public string WoNo { get; set; }
    public Nullable<long> QuoteTypeId { get; set; }
    public Nullable<int> PriorityNo { get; set; }
    public bool Active { get; set; }
    public Nullable<System.DateTime> WoDate { get; set; }
    public Nullable<long> QuoteID { get; set; }
    public Nullable<System.DateTime> WoDone { get; set; }
    public Nullable<long> WOScheduleListId { get; set; }
    public string StorageLocation { get; set; }

    public virtual QuoteType QuoteType { get; set; }
    public virtual Quote Quote { get; set; }
    public virtual WOScheduleList WOScheduleList { get; set; }
}

WoWcheduleVM.cs...

public partial class WoScheduleVM
{
    public long Id { get; set; }
    public string WoNo { get; set; }
    public Nullable<long> QuoteTypeId { get; set; }
    public Nullable<int> PriorityNo { get; set; }
    public bool Active { get; set; }
    public DateTime? WoDate { get; set; }
    public Nullable<long> QuoteID { get; set; }
    public DateTime? WoDone { get; set; }
    public Nullable<long> WOScheduleListId { get; set; }
    public string StorageLocation { get; set; }

    public string WoCust { get; set; } // extra property
    public string Lname { get; set; } // extra property

    public virtual QuoteType QuoteType { get; set; }
    public virtual Quote Quote { get; set; }
    public virtual WOScheduleList WOScheduleList { get; set; }
}

WOSchedulesController.cs

string cs = ConfigurationManager.ConnectionStrings["foxproTables"].ConnectionString;
OleDbConnection cn = new OleDbConnection(cs);
var wOSchedules = db.WOSchedules.Where(w => w.WoDone == null).Include(w => w.QuoteType);

var wOSchedulesVM = wOSchedules.Select(s => new ViewModels.WoScheduleVM()
  {
     Id = s.Id,
     WoNo = s.WoNo,
     QuoteTypeId = s.QuoteTypeId,
     PriorityNo = s.PriorityNo,
     Active = s.Active,
     WoDate = s.WoDate,
     QuoteID = s.QuoteID,
     WoDone = s.WoDone,
     WOScheduleListId = s.WOScheduleListId,
     StorageLocation = s.StorageLocation
   });

cn.Open();
foreach (var sch in wOSchedulesVM)
  {
    string conn = @"SELECT wo_cust, lname FROM womast INNER JOIN custmast ON womast.wo_cust = custmast.cust_id WHERE wo_no = '" + sch.WoNo + "'";
    OleDbCommand cmdWO = new OleDbCommand(conn, cn);
    OleDbDataReader rdr = cmdWO.ExecuteReader();
    while (rdr.Read())
    {
      sch.WoCust = ((string)rdr["wo_cust"]).Trim();
      sch.Lname = ((string)rdr["lname"]).Trim();
    }
  }
cn.Close();

return View(wOSchedulesVM.OrderByDescending(d => d.WoDate).ToList());
Beengie
  • 1,588
  • 4
  • 18
  • 36

1 Answers1

0

The problem is you're using foreach loop for iterating wOSchedulesVM collection, which renders the source collection immutable during iteration. The older documentation version explicitly explains that behavior:

The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add or remove items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.

Therefore, you should use for loop to be able to modify property values inside that collection, as shown in example below:

using (var OleDbConnection cn = new OleDbConnection(cs))
{
    cn.Open();
    string cmd = @"SELECT wo_cust, lname FROM womast INNER JOIN custmast ON womast.wo_cust = custmast.cust_id WHERE wo_no = @WoNo";

    // not sure if it's 'Count' property or 'Count()' method, depending on collection type
    for (int i = 0; i < wOSchedulesVM.Count; i++)
    {
        var sch = wOSchedulesVM[i];
        using (OleDbCommand cmdWO = new OleDbCommand(conn, cn))
        {
            cmd.Parameters.AddWithValue("@WoNo", sch.WoNo)
            OleDbDataReader rdr = cmdWO.ExecuteReader();
            if (rdr.HasRows)
            {
                while (rdr.Read())
                {
                    sch.WoCust = (!rdr.IsDbNull(0)) ? rdr.GetString(0).Trim() : string.Empty;
                    sch.Lname = (!rdr.IsDbNull(1)) ? rdr.GetString(1).Trim() : string.Empty;
                }
            }
        }
    }
}

Note: This example includes 3 additional aspects, i.e. parameterized query, checking row existence with HasRows property and checking against DBNull.Value with IsDbNull().

Related issue: What is the best way to modify a list in a 'foreach' loop?

Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61