Use the foreach for properties of class - c#

I'm writing an function to update a row in table (SQLite). At one time I only need to update certain columns of that row.
My Video class (and table) has these properties (and columns):
Id, Name, Lyric, Cover,Gendre, Url. ( they're all string)
Now, for example, I need to update the lyric and cover of 1 row in table , I'm using this code:
string id = // still keep the old id, this's the PK of table;
string lyric = //get new lyric;
string cover = // get new cover;
Video item = new Video(){Id = id, Lyric = lyric, Cover = cover};
SQLiteAccess.EditVideoInfo(item);
Here's the EditVideoInfo
public static void EditVideoInfo(Video item)
{
var conn = new SQLiteConnection(mypath);
using (conn)
{
var list = conn.Query<Video>("SELECT * FROM Video WHERE Id =?", item.Id);
if (list.Count >0)
{
var editItem = list.First(); // -> Get the item need to updated
/// Here's where I'm stuck
conn.Update(editItem);
}
}
}
So how can I read "foreach" each property of the new item and update to the old item's property if that property isn't null ?

Something like below.
var props = typeof(Video).GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.GetProperty|BindingFlags.SetProperty);
foreach (var prop in props) {
var propVal = prop.GetValue(item, null);
if (propVal != null)
prop.SetValue(editItem, propVal, null);
}

You can use reflection to get all the properties of the Video item (take a look at http://msdn.microsoft.com/en-us/library/kyaxdd3x(v=vs.110).aspx) but the solution would be slow and messy. Just write the test and update code for each property.

My first approach to do this is to create a dictionary
Dictionary<string, string> _properties = new Dictionary<string, string>();
_properties["id"] = "myID"
_properties["lyric"] = "some other string"
and then you can iterate through it with a foreach
foreach (var prop in _properties)
{
// do something with prop
}

Related

Modify excel custom variable with DocumentFormat.OpenXml C#

Following the steps from this post, I have used the following code to modify just one custom property from a .xslm file (excel with macros):
var newProp = new CustomDocumentProperty();
newProp.VTInt32 = new VTInt32("1");
newProp.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
newProp.Name = "CurrentVersionExported";
using (var document = SpreadsheetDocument.Open(excelPath, true))
{
var props = document.CustomFilePropertiesPart.Properties;
var prop = props.Where(p => ((CustomDocumentProperty)p).Name.Value == "CurrentVersionExported").FirstOrDefault();
// If the property exists, get the return value and then delete the property.
if (prop != null)
{
prop.Remove();
}
// Append the new property, and fix up all the property ID values.
props.AppendChild(newProp);
int pid = 2;
foreach (CustomDocumentProperty item in props)
{
item.PropertyId = pid++;
}
props.Save();
}
It works well but there are two things that I do not understand:
What is the pid? i believe it is the property ID, but I do not understand why it has to be 2 initially.
How should I know the initial format ID from my property? My excel does not have an XML schema so I have used the format ID from the post I linked before, I do not know if it is wrong or not to use that one.

Is there a way to loop through database using a datacontext to find and replace a value?

I have a list of email addresses that give a bumb if you send something to them, so they don't exist anymore. There a a lot of them and it is unclear where they are in a huge database.
Is there a way to loop through the database, through a datacontext, not knowing the table name or column name, and still find and replace the value?
I already have a collection of table names and column names put together (if needed)
I have tried a bunch of stuff like using reflection and other things.
Dictionary<string, List<string>> tablesWithColumns = new Dictionary<string, List<string>>();
var model = new System.Data.Linq.Mapping.AttributeMappingSource().GetModel(typeof(DataContext));
foreach (System.Data.Linq.Mapping.MetaTable modelTable in model.GetTables())
{
string tableName = modelTable.TableName;
tablesWithColumns.Add(tableName, new List<string>());
foreach (var dataMember in modelTable.RowType.DataMembers)
{
string columnName = dataMember.MappedName;
tablesWithColumns[tableName].Add(columnName);
}
}
Is there a way of using the following (pseudo):
string emailAdresThatHasToBeNull = "gmail#someemail.com";
using (DataContext dataContext = new DataContext())
{
foreach (KeyValuePair<string, List<string>> keyValuePair in tablesWithColumns)
{
string tableName = keyValuePair.Key;
foreach (string columnName in keyValuePair.Value)
{
var list = dataContext.(tableName).Columns(c => c.name == columnName).All(v => v == emailAdresThatHasToBeNull);
foreach (var entry in list)
{
entry = null;
}
}
}
dataContext.SubmitChanges();
}
The wanted result is everywhere the email address was is now NULL.

Adding to or updating an entity in a foreach loop takes too long time before calling SaveChanges()?

I have this method that saves an entity with its related items (many-to-many relationship),
private static void Save<T>(TbCommonHistoryLog log, List<T> lstDetails) where T : IHasSerial
{
foreach (var item in lstDetails.OrderBy(x => x.Serial))
{
var ser = SerializeObject(item);
var record = oContext.TbHistoryLog_Lists.FirstOrDefault(x => x.ListObjectJson == ser);
if (record == null) //add new list item
{
TbCommonHistoryLog_Lists listObject = new TbCommonHistoryLog_Lists()
{
ListObjectJson = SerializeObject(item)
};
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = listObject };
oContext.TbHistoryLogDetails.Add(details);
}
else //attach an existing list item
{
var o = oContext.TbHistoryLog_Lists.Find(record.Id);
oContext.TbHistoryLog_Lists.Attach(o);
var details = new TbCommonHistoryLogDetails { TbHistoryLog = log, TbHistoryLog_Lists = o };
oContext.TbHistoryLogDetails.Add(details);
}
}
oContext.BulkSaveChanges();
}
I have two tables: TbCommonHistoryLog, TbCommonHistoryLog_Lists, that are in many to many relationship, the joining table is TbCommonHistoryLogDetails,
What I'm doing here is an auditing for master-detail models, all audits are serialized to JSON in DB, I save the head object in the TbCommonHistoryLog table, and every list item in the TbHistoryLog_Lists table, in the mthod above I check if the list item is already exists in the database or not to avoid duplicating.
but this process takes more than 15 seconds which is a very long time, I can't figure out what am I doing wrong here.. please help?
For every single item in collection you're querying database. My suggestion is to save records in var, then ask the variable if the item is in database.
var databaseRecords = oContext.TbHistoryLog_Lists.ToList();
Then in the loop:
var record = databaseRecords.FirstOrDefault(x => x.ListObjectJson == ser);

Getting all children of specific page type

I have the following tree in EPI CMS:
[Root]
.
.
--[Lobby] ID=1
--Foo1
--Foo2
--Foo3
--[ContainerOfSubFoo] ID=2
--SubFoo1
--SubFoo2
--SubFoo3
I want when I edit Foo1, to have check boxes of all the SubFoo's.
What I have now is this:
private static List<SelectItem> GetSubFoos()
{
PageReference pRef = new PageReference(2); //(ID=2 is my container page - ContainerOfSubFoo)
PageData root = DataFactory.Instance.GetPage(pRef);
var pages = DataFactory.Instance.GetChildren<Models.Pages.SubFoo>(root.ContentLink);
List<SelectItem> targetsList = new List<SelectItem>();
foreach (var target in pages)
{
targetsList.Add(new SelectItem() { Value = target.ContentLink.ID.ToString(), Text = target.SubFooProperty });
}
return targetsList;
}
This works fine but I don't want to use ID=2, I want the GetSubFoos to go "up" (to Lobby) then go "down" to the first ContainerOfSubFoo and get all the children of SubFooType
The GetSubFoo method is on the Foo class
I can provide the code of the SelectionFactory if needed.
Another problem I see now is that the checkbox "V" does not save :/
(the string is saved with the values comma seperated but the checkboxes
are all unchecked
this was solved by adding .ToString() for the ID
From within the selection factory, you can obtain the current content via a handy extension method EPiServer.Cms.Shell.Extensions.FindOwnerContent() on the ExtendedMetadata that is passed in by EPiServer:
public virtual IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
var selections = new List<SelectItem>();
var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
var ownerContent = metadata.FindOwnerContent();
if (ownerContent is Foo)
{
var containerRoot = contentRepository.GetChildren<ContainerOfSubFoo>(ownerContent.ParentLink).FirstOrDefault();
var pageOptions = contentRepository.GetChildren<SubFoo>(containerRoot.ContentLink);
foreach (var target in pageOptions)
{
selections.Add(new SelectItem() { Value = target.ContentLink.ID.ToString(), Text = target.SubFooProperty });
}
}
return selections;
}
You can then traverse the page tree to find what you need.

Check same elements in two lists

I have a List and a ListItemCollection and want to check if there have the same elements.
First, I fill the ListItemCollection with Text and Value. (After a SQL Select)
ListItemCollection tempListName = new ListItemCollection();
ListItem temp_ListItem;
if (reader.HasRows)
{
while (reader.Read())
{
temp_ListItem = new ListItem(reader[1].ToString(), reader[0].ToString());
tempListName.Add(temp_ListItem);
}
}
and I have the List
List<string> tempList = new List<string>(ProfileArray);
with some values like {"1","4","5","7"}
now, I want to check, if the tempList have maybe some elements with the same value in tempListName and read the text from the value adn write it in a new list.
Note: Im using asp.net 2.0.
List.FindAll was already available in C# 2.0:
List<string> newList = tempList.FindAll(s => tempListName.FindByText(s) != null);
ListItemCollection.FindByText:
Use the FindByText method to search the collection for a ListItem with
a Text property that equals text specified by the text parameter. This
method performs a case-sensitive and culture-insensitive comparison.
This method does not do partial searches or wildcard searches. If an
item is not found in the collection using this criteria, null is
returned.
Real simple solution that you can customize and optimize as per your needs.
List<string> names = new List<string>(); // This will hold text for matched items found
foreach (ListItem item in tempListName)
{
foreach (string value in tempList)
{
if (value == item.Value)
{
names.Add(item.Text);
}
}
}
So, for a real simple example, consider something like this:
List<string> tempTextList = new List<string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now, just having a listing of the text values doesn't do you much good, so let's improve that a little:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(val, text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now you can actually find the text for a specific value from the dictionary. You might even want to declare that Dictionary<string, string> in a higher scope and use it elsewhere. If you were to declare it at a higher scope, you'd just change one line, this:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
to this:
tempTextList = new Dictionary<string, string>();
var resultList = new List<string>();
foreach (string listItem in tempList)
foreach (ListItem listNameItem in tempListName)
if (listNameItem.Value.Equals(listItem))
resultList.Add(listNameItem.Text);

Categories

Resources