SPWeb.Fields is empty when iterating through SPWebCollection - sharepoint-2007

I'm writing a command line application that checks the SPFieldCollection returned by the SPWeb.Fields property, but it's not behaving as I'd like. I have hundreds of SPWebs and it's definitely touching them all, but for all but the initial SPWeb, it's returning an empty Fields property. What am I doing wrong?
string siteUrl = "http://webroot/sitecoll";
using (SPSite siteCol = new SPSite(siteUrl))
{
using(SPWeb outerWeb = siteCol.OpenWeb())
{
foreach (SPWeb innerWeb in siteCol.AllWebs)
{
LogMessageToFile(String.Format("Checking {0}", innerWeb.Url)); //executed for each of the hundreds of innerWebs
if (innerWeb.Fields.ContainsField("Year"))
{
// Never accessed after the first time through because innerWeb.Fields is empty
}
}
}
}

SPweb.Fields live at the site collection level.
Unless you specifically create the fields at the subsite levels you will get 0 returned.

Related

Grails edit working abnormally updating database on value assign

I am using grails-2.1.1. When I load the edit page, I am assigning some value in the edit action in controller. But it is updating my table! although I am not saving. How can I stop it?
Here is my code below. My edit action in controller:
def edit() {
def accTxnMstInstance = AccTxnMst.get(params.id)
if (!accTxnMstInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'accTxnMst.label', default: 'AccTxnMst'), params.id])
redirect(action: "list")
return
}
accTxnMstInstance?.accTxnDtls?.each {
if (it?.debitCoa != null && it?.debitCoa != "") {
String debitCoaVal = ""
List<String> items = Arrays.asList(it?.debitCoa?.split("\\s*~\\s*"))
items.each {
List itemList = new ArrayList()
List<String> subItems = Arrays.asList(it.split("\\^"))
subItems.each {
itemList.add(it)
}
itemList.add("false")
itemList.add("0")
itemList.each {
debitCoaVal += it.toString() + "^"
}
debitCoaVal += "~"
}
it?.debitCoa = debitCoaVal
debitCoaVal = ""
}
if (it?.creditCoa != null && it?.creditCoa != "") {
String creditCoaVal = ""
List<String> items = Arrays.asList(it?.creditCoa?.split("\\s*~\\s*"))
items.each {
List itemList = new ArrayList()
List<String> subItems = Arrays.asList(it.split("\\^"))
subItems.each {
itemList.add(it)
}
itemList.add("false")
itemList.add("0")
itemList.each {
creditCoaVal += it.toString() + "^"
}
creditCoaVal += "~"
}
it?.creditCoa = creditCoaVal
creditCoaVal = ""
}
}
[accTxnMstInstance: accTxnMstInstance]
}
You can see that I am not saving after assigning the value just passing to view.
Grails uses the Open Session In View (OSIV) pattern, where at the beginning of the web request a Hibernate session is opened (and stored in a thread-local to make it easily accessible) and at the end of the request as long as there wasn't an exception, the Hibernate session is flushed and closed. During any flush, Hibernate looks at all "active" object instances and loops through each persistent property to see if it is "dirty". If so, even though you didn't explicitly call save(), your changes will be pushed to the database for you. This is possible because when Hibernate creates an instance from a database row it caches the original data to compare later to the potentially-changed instance properties.
A lot of the time this is helpful behavior, but in cases like this it gets in the way. There are lots of fixes though. One drastic one is to disable OSIV, but this is generally a bad idea unless you know what you're doing. In this case there are two things you can try that should work.
One is to change AccTxnMst.get(params.id) to AccTxnMst.read(params.id). This will not cause the instance to be strictly "read-only" because you can still explicitly call save() and if something was modified, all of the instance changes will be persisted. But the caching of the original data isn't done for instances retrieved using read(), and there's no dirty checking during flush for these instances (which isn't possible anyway since there's no cached data to compare with).
Using read() is a good idea in general when retrieving instances that are not going to be updated (whether you make property changes or not), and makes the code more self-documenting.
Another option is to call discard() on the instance before the controller action finishes. This "detaches" the instance from the Hibernate session, so when the OSIV filter runs at the end of the request and flushes the Hibernate session, your instance won't be considered dirty since Hibernate won't have access to it.
read() only makes sense for individual instances retrieved by id, whereas discard() is useful for any instance, e.g. if they're in a mapped collection or were retrieved by a non-id query (e.g. a dynamic finder, criteria query, etc.)

DevExpress MVC PivotGrid Custom Actions Keep Firing

I am using a DevExpress MVC Pivot Grid and trying to work out some problems with the loading and saving of layouts. So far I have the following:
I have set my CustomActionRouteValues in the PivotGridSettings as follows:
CustomActionRouteValues = new { Controller = "Home", Action = "PivotGridCustomCallback" },
Which points to the following:
public ActionResult PivotGridCustomCallback(string action, string reportName)
{
if (string.IsNullOrEmpty(reportName))
{
reportName = "Report 1";
}
var settings = PivotGridLayoutHelper.DefaultPivotGridSettings;
if (action == "Save")
{
// TODO: Find a better solution than this. At the moment, if Save is called once, it is then called again every time the user changes the layout.. which is why we have the 'saved' variable here.
bool saved = false;
settings.AfterPerformCallback = (sender, e) =>
{
if (saved)
{
return;
}
SaveLayout(((MVCxPivotGrid)sender).SaveLayoutToString(), reportName);
saved = true;
};
}
else if (action == "Load")
{
// TODO: Find a better solution than this. At the moment, if Load is called once, it is then called again every time the user changes the layout.. which is why we have the 'loaded' variable here.
bool loaded = false;
string layoutString = LoadLayout(reportName);
if (!string.IsNullOrEmpty(layoutString))
{
settings.BeforeGetCallbackResult = (sender, e) =>
{
if (loaded)
{
return;
}
((MVCxPivotGrid)sender).LoadLayoutFromString(layoutString, PivotGridWebOptionsLayout.DefaultLayout);
loaded = true;
};
}
}
ViewBag.PivotSettings = settings;
return PartialView("PivotPartial");
}
The problem, as you can see in the code comments, is that after performing an action just one time, it then gets called EVERY time I make any sort of change. So, for example... say I load a report.. that's fine.. but then when I try expand something or add a field.. or do ANYTHING, nothing seems to happen on the UI.. and I figured out that's because immediately, this code gets called again:
settings.BeforeGetCallbackResult = (sender, e) =>
{
((MVCxPivotGrid)sender).LoadLayoutFromString(layoutString, PivotGridWebOptionsLayout.DefaultLayout);
};
That just keeps resetting the values to the saved layout, which means the UI looks like it's unresponsive when trying to change anything.
This is why I now have the boolean variable called loaded to check if it's already loaded. That works.. but it's an ugly hack.. because it's making unnecessary trips to the server each and every time the user does anything on the pivot grid.
Surely there must be a way to prevent these actions from firing all the time?

Asp.Net MVC 5 saving rss feed to database

I am getting rss feed from a another website and in case that website shut down, I don't want to get an error. So in order to avoid from error I am trying to save rss feeds to database and if the rss server shuts down I will be able to get feed from my database.
I also want to keep only 6 feed in database. If new feed comes I want to delete the last feed by PublishDate
public static List<Rss.News> GetRssFeed(ApplicationDbContext db)
{
try
{
XDocument feedXml = XDocument.Load("http://www.gib.gov.tr/
rss/haberguncel.php");
var feeds = from feed in feedXml.Descendants("item")
select new Rss.News
{
Title = feed.Element("title").Value,
Link = feed.Element("link").Value,
Description = feed.Element("description").Value,
PublishDate=feed.Element("pubdate").Value
};
int counter = 0;
var itemE = db.News.FirstOrDefault();
if (itemE != feeds.First())
{
foreach (var itemC in feeds)
{
if (!db.News.Contains(itemC))
{
db.News.Add(itemC);
db.SaveChanges();
counter += 1;
}
else
{
break;
}
if (counter == 6) { break; }
}
}
return feeds.ToList();
}
catch (Exception)
{
// i will get data from database here.
}
}
I am getting this error when I run this code:
Unable to create a constant value of type
'...Models.Rss+News'. Only primitive types or enumeration
types are supported in this context.
The error is resulting from this line:
if (!db.News.Contains(itemC))
In order to do this type of evaluation at the database level, Entity Framework must be able to convert item being compared (itemC) into a constant value, which it cannot do with this type, hence your error. You can try casting db.News to a list, first, which would switch the evaluation over to in-memory instead at the the database, i.e.:
var news = db.News.ToList();
if (news.Contains(itemC))
However, you'll have to evaluate how that might affect your application's performance. Alternatively, you simply query on a particular value that you determine as the "key" for lookup. For example, you might say that Link will only ever match if it's the same item, so based on that:
if (!db.News.Any(m => m.Link == itemC.Link))

Saving an array of new entities via breeze context "saveChanges"

If I have an entity that contains a 1:n collection of another entity then what is the correct way to save the collection?
I've got to this (code not finalised/checked yet):
return datacontext.savechanges([parentEntity]).then(function() {
for (var i=0;i < childArray.length;i++) {
var newChildEntity;
return datacontext.makeNewChildEntity(newChildEntity).then(function() {
newChildEntity.parentID(parentEntity().id());
...
//set other newChildEntity properties
...
return datacontext.savechanges([newChildEntity]).then(function() {
//set finished flag and exit function...
}
}
}
}
"datacontext" is an async module with various exposed methods including creating a new childEntity.
Whereas I haven't tested this yet, it kind of logically works for me, but am I right to be looping around in the createEntity/modifyEntity/saveEntity loop for each new child object I want to add to the collection of childEntities? Is this the only way to do it or is there a way of doing all childEntities in one hit?
The "parentID" is an identity field - store generated so I have to wait for the intitial parent save to finish before I can use the returned ID.
Edited to add: I don't think I need to have a "then" on the end of the async newChildEntity save, do I? I need it to be async still so it can go off and loop through multiple childEntities quickly as the dependent bit is the id from the parent record that's already generated. All the child records share the same parentID so I can set off multiple saves without waiting for the saveChanges method to respond, right?
Breeze's EntityManager.saveChanges can save any number of entities in a single call, which is substantially more performant than trying to call saveChanges once per entity.
Also, I'm not sure why your makeNewChildEntity needs to be asynchronous, Breeze's EntityManager.createEntity itself is synchronous, so I think that all you need to do is something like this.
return datacontext.savechanges([parentEntity]).then(function() {
var listOfEntities = [parentEntity];
for (var i=0;i < childArray.length;i++) {
// synchronous makeNewChildEntity
var newChildEntity = datacontext.makeNewChildEntity();
newChildEntity.parentID(parentEntity().id());
...
//set other newChildEntity properties
...
listOfEntities.push(newChildEntity);
}
// alternatively use datacontext.savechanges(listOfEntities).then(...)
return datacontext.savechanges().then(function() {
//set finished flag and exit function...
}
}
}

Method not called when using yield return

I'm having a little trouble with a method in which I use yield return this doesn't work...
public IEnumerable<MyClass> SomeMethod(int aParam)
{
foreach(DataRow row in GetClassesFromDB(aParam).Rows)
{
yield return new MyClass((int)row["Id"], (string)row["SomeString"]);
}
}
The above code never runs, when the call is made to this method it just steps over it.
However if I change to...
public IEnumerable<MyClass> SomeMethod(int aParam)
{
IList<MyClass> classes = new List<MyClass>();
foreach(DataRow row in GetClassesFromDB(aParam).Rows)
{
classes.Add(new MyClass((int)rows["Id"], (string)row["SomeString"]);
}
return classes;
}
It works just fine.
I don't understand why the first method never runs, could you help me in understanding what is happening here?
The "yield" version is only "run" when the caller actually starts to enumerate the returned collection.
If, for instance, you only get the collection:
var results = SomeObject.SomeMethod (5);
and don't do anything with it, the SomeMethod will not execute.
Only when you start enumerating the results collection, it will hit.
foreach (MyClass c in results)
{
/* Now it strikes */
}
yield return methods are actually converted into state machine classes that retrieve information lazily - only when you actually ask for it. That means that in order to actually pull data, you have to iterate over the result of your method.
// Gives you an iterator object that hasn't done anything yet
IEnumerable<MyClass> list = SomeMethod();
// Enumerate over the object
foreach (var item in list ) {
// Only here will the data be retrieved.
// The method will stop on yield return every time the foreach loops.
}
The reason it runs in the second case is because there's no yield block, and thus the entire method runs in one go.
In this specific case, it's unlikely that you'll have any advantage to use an iterator block over a regular one because your GetClassesFromDb() isn't one either. This means that it will retrieve all the data at the same time first time it runs. Iterator blocks are best used when you can access items one at a time, because that way you can stop if you don't need them anymore.
I had to learn in a near disastrous way how cool/dangerous yield is when I decided to make our company's parser read incoming data lazily. Fortunately only one of the handful of our implementing functions actually used the yield keyword. Took a few days to realize it was quietly not doing any work at all.
The yield keyword it will be as lazy as it possibly can, including skipping over the method altogether if you don't put it to work with something like .ToList() or .FirstOrDefault() or .Any()
Below are two variations, one using the keyword and one returning a straight-up list. One won't even bother to execute, while the other will, even though they seem the same.
public class WhatDoesYieldDo
{
public List<string> YieldTestResults;
public List<string> ListTestResults;
[TestMethod]
public void TestMethod1()
{
ListTest();
Assert.IsTrue(ListTestResults.Any());
YieldTest();
Assert.IsTrue(YieldTestResults.Any());
}
public IEnumerable<string> YieldTest()
{
YieldTestResults = new List<string>();
for (var i = 0; i < 10; i++)
{
YieldTestResults.Add(i.ToString(CultureInfo.InvariantCulture));
yield return i.ToString(CultureInfo.InvariantCulture);
}
}
public IEnumerable<string> ListTest()
{
ListTestResults = new List<string>();
for (var i = 0; i < 10; i++)
{
ListTestResults.Add(i.ToString(CultureInfo.InvariantCulture));
}
return ListTestResults;
}
}
Moral of the story: Make sure that if have a method that returns IEnumerable and you use yield in that method, you have something that will iterate over the results, or the method won't execute at all.

Resources